xref: /webtrees/app/Module/HourglassChartModule.php (revision a21e5374db7cb1b635bdba285b001099d85f2390)
1<?php
2/**
3 * webtrees: online genealogy
4 * Copyright (C) 2019 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\Module;
19
20use Fisharebest\Webtrees\Auth;
21use Fisharebest\Webtrees\Contracts\UserInterface;
22use Fisharebest\Webtrees\Family;
23use Fisharebest\Webtrees\I18N;
24use Fisharebest\Webtrees\Individual;
25use Fisharebest\Webtrees\Menu;
26use Fisharebest\Webtrees\Tree;
27use Illuminate\Support\Collection;
28use Psr\Http\Message\ResponseInterface;
29use Psr\Http\Message\ServerRequestInterface;
30use function app;
31use function response;
32use function view;
33
34/**
35 * Class HourglassChartModule
36 */
37class HourglassChartModule extends AbstractModule implements ModuleChartInterface
38{
39    use ModuleChartTrait;
40
41    // Defaults
42    private const DEFAULT_GENERATIONS         = '3';
43    private const DEFAULT_MAXIMUM_GENERATIONS = '9';
44
45    // Limits
46    private const MAXIMUM_GENERATIONS = 10;
47    private const MINIMUM_GENERATIONS = 2;
48
49    /**
50     * How should this module be identified in the control panel, etc.?
51     *
52     * @return string
53     */
54    public function title(): string
55    {
56        /* I18N: Name of a module/chart */
57        return I18N::translate('Hourglass chart');
58    }
59
60    /**
61     * A sentence describing what this module does.
62     *
63     * @return string
64     */
65    public function description(): string
66    {
67        /* I18N: Description of the “HourglassChart” module */
68        return I18N::translate('An hourglass chart of an individual’s ancestors and descendants.');
69    }
70
71    /**
72     * CSS class for the URL.
73     *
74     * @return string
75     */
76    public function chartMenuClass(): string
77    {
78        return 'menu-chart-hourglass';
79    }
80
81    /**
82     * Return a menu item for this chart - for use in individual boxes.
83     *
84     * @param Individual $individual
85     *
86     * @return Menu|null
87     */
88    public function chartBoxMenu(Individual $individual): ?Menu
89    {
90        return $this->chartMenu($individual);
91    }
92
93    /**
94     * A form to request the chart parameters.
95     *
96     * @param ServerRequestInterface $request
97     * @param Tree                   $tree
98     * @param UserInterface          $user
99     *
100     * @return ResponseInterface
101     */
102    public function getChartAction(ServerRequestInterface $request, Tree $tree, UserInterface $user): ResponseInterface
103    {
104        $ajax       = (bool) $request->get('ajax');
105        $xref       = $request->get('xref', '');
106        $individual = Individual::getInstance($xref, $tree);
107
108        Auth::checkIndividualAccess($individual);
109        Auth::checkComponentAccess($this, 'chart', $tree, $user);
110
111        $generations = (int) $request->get('generations', self::DEFAULT_GENERATIONS);
112
113        $generations = min($generations, self::MAXIMUM_GENERATIONS);
114        $generations = max($generations, self::MINIMUM_GENERATIONS);
115
116        $show_spouse = (bool) $request->get('show_spouse');
117
118        if ($ajax) {
119            return $this->chart($individual, $generations, $show_spouse);
120        }
121
122        $ajax_url = $this->chartUrl($individual, [
123            'ajax'        => true,
124            'generations' => $generations,
125            'show_spouse' => $show_spouse,
126        ]);
127
128        return $this->viewResponse('modules/hourglass-chart/page', [
129            'ajax_url'            => $ajax_url,
130            'generations'         => $generations,
131            'individual'          => $individual,
132            'maximum_generations' => self::MAXIMUM_GENERATIONS,
133            'minimum_generations' => self::MINIMUM_GENERATIONS,
134            'module_name'         => $this->name(),
135            'show_spouse'         => $show_spouse,
136            'title'               => $this->chartTitle($individual),
137        ]);
138    }
139
140    /**
141     * Generate the initial generations of the chart
142     *
143     * @param Individual $individual
144     * @param int        $generations
145     * @param bool       $show_spouse
146     *
147     * @return ResponseInterface
148     */
149    protected function chart(Individual $individual, int $generations, bool $show_spouse): ResponseInterface
150    {
151        $this->layout = 'layouts/ajax';
152
153        return $this->viewResponse('modules/hourglass-chart/chart', [
154            'generations' => $generations,
155            'individual'  => $individual,
156            'show_spouse' => $show_spouse,
157        ]);
158    }
159
160    /**
161     * Generate an extension to the chart
162     *
163     * @param ServerRequestInterface $request
164     *
165     * @return ResponseInterface
166     */
167    public function getAncestorsAction(ServerRequestInterface $request): ResponseInterface
168    {
169        $tree = app(Tree::class);
170        $xref = $request->getQueryParams()['xref'] ?? '';
171
172        $family = Family::getInstance($xref, $tree);
173        Auth::checkFamilyAccess($family);
174
175        return response(view('modules/hourglass-chart/parents', [
176            'family'      => $family,
177            'generations' => 1,
178        ]));
179    }
180
181    /**
182     * Generate an extension to the chart
183     *
184     * @param ServerRequestInterface $request
185     *
186     * @return ResponseInterface
187     */
188    public function getDescendantsAction(ServerRequestInterface $request): ResponseInterface
189    {
190        $tree = app(Tree::class);
191        $xref = $request->getQueryParams()['xref'] ?? '';
192
193        $show_spouse = (bool) ($request->getQueryParams()['show_spouse'] ?? false);
194        $individual  = Individual::getInstance($xref, $tree);
195
196        Auth::checkIndividualAccess($individual);
197
198        $children = $individual->spouseFamilies()->map(static function (Family $family): Collection {
199            return $family->children();
200        })->flatten();
201
202        return response(view('modules/hourglass-chart/children', [
203            'children'    => $children,
204            'generations' => 1,
205            'show_spouse' => $show_spouse,
206        ]));
207    }
208}
209