xref: /webtrees/app/Module/DescendancyChartModule.php (revision 3976b4703df669696105ed6b024b96d433c8fbdb)
1168ff6f3Sric2016<?php
2*3976b470SGreg Roach
3168ff6f3Sric2016/**
4168ff6f3Sric2016 * webtrees: online genealogy
58fcd0d32SGreg Roach * Copyright (C) 2019 webtrees development team
6168ff6f3Sric2016 * This program is free software: you can redistribute it and/or modify
7168ff6f3Sric2016 * it under the terms of the GNU General Public License as published by
8168ff6f3Sric2016 * the Free Software Foundation, either version 3 of the License, or
9168ff6f3Sric2016 * (at your option) any later version.
10168ff6f3Sric2016 * This program is distributed in the hope that it will be useful,
11168ff6f3Sric2016 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12168ff6f3Sric2016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13168ff6f3Sric2016 * GNU General Public License for more details.
14168ff6f3Sric2016 * You should have received a copy of the GNU General Public License
15168ff6f3Sric2016 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16168ff6f3Sric2016 */
17e7f56f2aSGreg Roachdeclare(strict_types=1);
18e7f56f2aSGreg Roach
19168ff6f3Sric2016namespace Fisharebest\Webtrees\Module;
20168ff6f3Sric2016
2154452b04SGreg Roachuse Fisharebest\Webtrees\Auth;
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
5757ab2231SGreg Roach    /** @var ChartService */
5857ab2231SGreg Roach    private $chart_service;
5957ab2231SGreg Roach
6057ab2231SGreg Roach    /**
6157ab2231SGreg Roach     * DescendancyChartModule constructor.
6257ab2231SGreg Roach     *
6357ab2231SGreg Roach     * @param ChartService $chart_service
6457ab2231SGreg Roach     */
65*3976b470SGreg Roach    public function __construct(ChartService $chart_service)
66*3976b470SGreg Roach    {
6757ab2231SGreg Roach        $this->chart_service = $chart_service;
6857ab2231SGreg Roach    }
6957ab2231SGreg Roach
70168ff6f3Sric2016    /**
710cfd6963SGreg Roach     * How should this module be identified in the control panel, etc.?
72168ff6f3Sric2016     *
73168ff6f3Sric2016     * @return string
74168ff6f3Sric2016     */
7549a243cbSGreg Roach    public function title(): string
76c1010edaSGreg Roach    {
77bbb76c12SGreg Roach        /* I18N: Name of a module/chart */
78bbb76c12SGreg Roach        return I18N::translate('Descendants');
79168ff6f3Sric2016    }
80168ff6f3Sric2016
81168ff6f3Sric2016    /**
82168ff6f3Sric2016     * A sentence describing what this module does.
83168ff6f3Sric2016     *
84168ff6f3Sric2016     * @return string
85168ff6f3Sric2016     */
8649a243cbSGreg Roach    public function description(): string
87c1010edaSGreg Roach    {
88bbb76c12SGreg Roach        /* I18N: Description of the “DescendancyChart” module */
89bbb76c12SGreg Roach        return I18N::translate('A chart of an individual’s descendants.');
90168ff6f3Sric2016    }
91168ff6f3Sric2016
92168ff6f3Sric2016    /**
93377a2979SGreg Roach     * CSS class for the URL.
94377a2979SGreg Roach     *
95377a2979SGreg Roach     * @return string
96377a2979SGreg Roach     */
97377a2979SGreg Roach    public function chartMenuClass(): string
98377a2979SGreg Roach    {
99377a2979SGreg Roach        return 'menu-chart-descendants';
100377a2979SGreg Roach    }
101377a2979SGreg Roach
102377a2979SGreg Roach    /**
1034eb71cfaSGreg Roach     * Return a menu item for this chart - for use in individual boxes.
1044eb71cfaSGreg Roach     *
10560bc3e3fSGreg Roach     * @param Individual $individual
10660bc3e3fSGreg Roach     *
1074eb71cfaSGreg Roach     * @return Menu|null
1084eb71cfaSGreg Roach     */
109377a2979SGreg Roach    public function chartBoxMenu(Individual $individual): ?Menu
110c1010edaSGreg Roach    {
111e6562982SGreg Roach        return $this->chartMenu($individual);
112e6562982SGreg Roach    }
113e6562982SGreg Roach
114e6562982SGreg Roach    /**
115e6562982SGreg Roach     * The title for a specific instance of this chart.
116e6562982SGreg Roach     *
117e6562982SGreg Roach     * @param Individual $individual
118e6562982SGreg Roach     *
119e6562982SGreg Roach     * @return string
120e6562982SGreg Roach     */
121e6562982SGreg Roach    public function chartTitle(Individual $individual): string
122e6562982SGreg Roach    {
123e6562982SGreg Roach        /* I18N: %s is an individual’s name */
12439ca88baSGreg Roach        return I18N::translate('Descendants of %s', $individual->fullName());
125e6562982SGreg Roach    }
126e6562982SGreg Roach
127e6562982SGreg Roach    /**
12854452b04SGreg Roach     * A form to request the chart parameters.
12954452b04SGreg Roach     *
1306ccdf4f0SGreg Roach     * @param ServerRequestInterface $request
13154452b04SGreg Roach     *
1326ccdf4f0SGreg Roach     * @return ResponseInterface
13354452b04SGreg Roach     */
13457ab2231SGreg Roach    public function getChartAction(ServerRequestInterface $request): ResponseInterface
13554452b04SGreg Roach    {
13657ab2231SGreg Roach        $tree       = $request->getAttribute('tree');
13757ab2231SGreg Roach        $user       = $request->getAttribute('user');
1380b93976aSGreg Roach        $ajax       = $request->getQueryParams()['ajax'] ?? '';
13916e8b6e8SGreg Roach        $xref       = $request->getQueryParams()['xref'] ?? '';
14054452b04SGreg Roach        $individual = Individual::getInstance($xref, $tree);
14154452b04SGreg Roach
14254452b04SGreg Roach        Auth::checkIndividualAccess($individual);
1439867b2f0SGreg Roach        Auth::checkComponentAccess($this, 'chart', $tree, $user);
14454452b04SGreg Roach
14531e26437SGreg Roach        $chart_style = $request->getQueryParams()['chart_style'] ?? self::DEFAULT_STYLE;
14616e8b6e8SGreg Roach        $generations = (int) ($request->getQueryParams()['generations'] ?? self::DEFAULT_GENERATIONS);
14754452b04SGreg Roach
148e759aebbSGreg Roach        $generations = min($generations, self::MAXIMUM_GENERATIONS);
149e759aebbSGreg Roach        $generations = max($generations, self::MINIMUM_GENERATIONS);
15054452b04SGreg Roach
1510b93976aSGreg Roach        if ($ajax === '1') {
15257ab2231SGreg Roach            return $this->chart($request);
15354452b04SGreg Roach        }
15454452b04SGreg Roach
15554452b04SGreg Roach        $ajax_url = $this->chartUrl($individual, [
15654452b04SGreg Roach            'chart_style' => $chart_style,
15754452b04SGreg Roach            'generations' => $generations,
1589b5537c3SGreg Roach            'ajax'        => true,
15954452b04SGreg Roach        ]);
16054452b04SGreg Roach
1619b5537c3SGreg Roach        return $this->viewResponse('modules/descendancy_chart/page', [
16254452b04SGreg Roach            'ajax_url'            => $ajax_url,
16354452b04SGreg Roach            'chart_style'         => $chart_style,
16454452b04SGreg Roach            'chart_styles'        => $this->chartStyles(),
165e759aebbSGreg Roach            'default_generations' => self::DEFAULT_GENERATIONS,
16654452b04SGreg Roach            'generations'         => $generations,
16754452b04SGreg Roach            'individual'          => $individual,
168e759aebbSGreg Roach            'maximum_generations' => self::MAXIMUM_GENERATIONS,
169e759aebbSGreg Roach            'minimum_generations' => self::MINIMUM_GENERATIONS,
17026684e68SGreg Roach            'module_name'         => $this->name(),
17154452b04SGreg Roach            'title'               => $this->chartTitle($individual),
17254452b04SGreg Roach        ]);
17354452b04SGreg Roach    }
17454452b04SGreg Roach
17554452b04SGreg Roach    /**
1766ccdf4f0SGreg Roach     * @param ServerRequestInterface $request
17754452b04SGreg Roach     *
1786ccdf4f0SGreg Roach     * @return ResponseInterface
17954452b04SGreg Roach     */
18057ab2231SGreg Roach    public function chart(ServerRequestInterface $request): ResponseInterface
18154452b04SGreg Roach    {
18254452b04SGreg Roach        $this->layout = 'layouts/ajax';
18354452b04SGreg Roach
18457ab2231SGreg Roach        $tree       = $request->getAttribute('tree');
18516e8b6e8SGreg Roach        $xref       = $request->getQueryParams()['xref'];
18654452b04SGreg Roach        $individual = Individual::getInstance($xref, $tree);
18754452b04SGreg Roach
18854452b04SGreg Roach        Auth::checkIndividualAccess($individual);
18954452b04SGreg Roach
19031e26437SGreg Roach        $chart_style = $request->getQueryParams()['chart_style'];
19116e8b6e8SGreg Roach        $generations = (int) $request->getQueryParams()['generations'];
19254452b04SGreg Roach
193e759aebbSGreg Roach        $generations = min($generations, self::MAXIMUM_GENERATIONS);
194e759aebbSGreg Roach        $generations = max($generations, self::MINIMUM_GENERATIONS);
19554452b04SGreg Roach
19654452b04SGreg Roach        switch ($chart_style) {
1970f1e0f10SGreg Roach            case self::CHART_STYLE_TREE:
19854452b04SGreg Roach            default:
1990f1e0f10SGreg Roach                return response(view('modules/descendancy_chart/tree', ['individual' => $individual, 'generations' => $generations, 'daboville' => '1']));
20054452b04SGreg Roach
20154452b04SGreg Roach            case self::CHART_STYLE_INDIVIDUALS:
20257ab2231SGreg Roach                $individuals = $this->chart_service->descendants($individual, $generations - 1);
20354452b04SGreg Roach
20454452b04SGreg Roach                return $this->descendantsIndividuals($tree, $individuals);
20554452b04SGreg Roach
20654452b04SGreg Roach            case self::CHART_STYLE_FAMILIES:
20757ab2231SGreg Roach                $families = $this->chart_service->descendantFamilies($individual, $generations - 1);
20854452b04SGreg Roach
20954452b04SGreg Roach                return $this->descendantsFamilies($tree, $families);
21054452b04SGreg Roach        }
21154452b04SGreg Roach    }
21254452b04SGreg Roach
21354452b04SGreg Roach    /**
21454452b04SGreg Roach     * Show a tabular list of individual descendants.
21554452b04SGreg Roach     *
21654452b04SGreg Roach     * @param Tree       $tree
21754452b04SGreg Roach     * @param Collection $individuals
21854452b04SGreg Roach     *
2196ccdf4f0SGreg Roach     * @return ResponseInterface
22054452b04SGreg Roach     */
2216ccdf4f0SGreg Roach    private function descendantsIndividuals(Tree $tree, Collection $individuals): ResponseInterface
22254452b04SGreg Roach    {
22354452b04SGreg Roach        $this->layout = 'layouts/ajax';
22454452b04SGreg Roach
22554452b04SGreg Roach        return $this->viewResponse('lists/individuals-table', [
22654452b04SGreg Roach            'individuals' => $individuals,
22754452b04SGreg Roach            'sosa'        => false,
22854452b04SGreg Roach            'tree'        => $tree,
22954452b04SGreg Roach        ]);
23054452b04SGreg Roach    }
23154452b04SGreg Roach
23254452b04SGreg Roach    /**
23354452b04SGreg Roach     * Show a tabular list of individual descendants.
23454452b04SGreg Roach     *
23554452b04SGreg Roach     * @param Tree       $tree
23654452b04SGreg Roach     * @param Collection $families
23754452b04SGreg Roach     *
2386ccdf4f0SGreg Roach     * @return ResponseInterface
23954452b04SGreg Roach     */
2406ccdf4f0SGreg Roach    private function descendantsFamilies(Tree $tree, Collection $families): ResponseInterface
24154452b04SGreg Roach    {
24254452b04SGreg Roach        $this->layout = 'layouts/ajax';
24354452b04SGreg Roach
24454452b04SGreg Roach        return $this->viewResponse('lists/families-table', [
24554452b04SGreg Roach            'families' => $families,
24654452b04SGreg Roach            'tree'     => $tree,
24754452b04SGreg Roach        ]);
24854452b04SGreg Roach    }
24954452b04SGreg Roach
25054452b04SGreg Roach    /**
25154452b04SGreg Roach     * This chart can display its output in a number of styles
25254452b04SGreg Roach     *
2534db4b4a9SGreg Roach     * @return string[]
25454452b04SGreg Roach     */
25554452b04SGreg Roach    private function chartStyles(): array
25654452b04SGreg Roach    {
25754452b04SGreg Roach        return [
2580f1e0f10SGreg Roach            self::CHART_STYLE_TREE        => I18N::translate('Tree'),
25954452b04SGreg Roach            self::CHART_STYLE_INDIVIDUALS => I18N::translate('Individuals'),
26054452b04SGreg Roach            self::CHART_STYLE_FAMILIES    => I18N::translate('Families'),
26154452b04SGreg Roach        ];
262e6562982SGreg Roach    }
263168ff6f3Sric2016}
264