Passed
Push — master ( 01202f...713784 )
by Greg
07:38
created

HourglassChartModule::getChartAction()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 37
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 2
eloc 26
nc 2
nop 1
dl 0
loc 37
rs 9.504
c 2
b 0
f 0

2 Methods

Rating   Name   Duplication   Size   Complexity  
A HourglassChartModule::chartTitle() 0 4 1
A HourglassChartModule::chartBoxMenu() 0 3 1
1
<?php
2
3
/**
4
 * webtrees: online genealogy
5
 * Copyright (C) 2019 webtrees development team
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
 * GNU General Public License for more details.
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16
 */
17
declare(strict_types=1);
18
19
namespace Fisharebest\Webtrees\Module;
20
21
use Aura\Router\RouterContainer;
22
use Fig\Http\Message\RequestMethodInterface;
23
use Fisharebest\Webtrees\Auth;
24
use Fisharebest\Webtrees\Family;
25
use Fisharebest\Webtrees\I18N;
26
use Fisharebest\Webtrees\Individual;
27
use Fisharebest\Webtrees\Menu;
28
use Illuminate\Support\Collection;
29
use Psr\Http\Message\ResponseInterface;
30
use Psr\Http\Message\ServerRequestInterface;
31
use Psr\Http\Server\RequestHandlerInterface;
32
33
use function response;
34
use function view;
35
36
/**
37
 * Class HourglassChartModule
38
 */
39
class HourglassChartModule extends AbstractModule implements ModuleChartInterface, RequestHandlerInterface
40
{
41
    use ModuleChartTrait;
42
43
    private const ROUTE_NAME = 'hourglass-chart';
44
    private const ROUTE_URL  = '/tree/{tree}/hourglass-{generations}-{spouses}/{xref}';
45
46
    // Defaults
47
    private const   DEFAULT_GENERATIONS = '3';
48
    private const   DEFAULT_SPOUSES     = false;
49
    protected const DEFAULT_PARAMETERS  = [
50
        'generations' => self::DEFAULT_GENERATIONS,
51
        'spouses'     => self::DEFAULT_SPOUSES,
52
    ];
53
54
    // Limits
55
    protected const MINIMUM_GENERATIONS = 2;
56
    protected const MAXIMUM_GENERATIONS = 10;
57
58
    /**
59
     * Initialization.
60
     *
61
     * @param RouterContainer $router_container
62
     */
63
    public function boot(RouterContainer $router_container)
64
    {
65
        $router_container->getMap()
66
            ->get(self::ROUTE_NAME, self::ROUTE_URL, self::class)
67
            ->allows(RequestMethodInterface::METHOD_POST)
68
            ->tokens([
69
                'generations' => '\d+',
70
                'spouses'     => '1?',
71
            ]);
72
    }
73
74
    /**
75
     * How should this module be identified in the control panel, etc.?
76
     *
77
     * @return string
78
     */
79
    public function title(): string
80
    {
81
        /* I18N: Name of a module/chart */
82
        return I18N::translate('Hourglass chart');
83
    }
84
85
    /**
86
     * A sentence describing what this module does.
87
     *
88
     * @return string
89
     */
90
    public function description(): string
91
    {
92
        /* I18N: Description of the “HourglassChart” module */
93
        return I18N::translate('An hourglass chart of an individual’s ancestors and descendants.');
94
    }
95
96
    /**
97
     * CSS class for the URL.
98
     *
99
     * @return string
100
     */
101
    public function chartMenuClass(): string
102
    {
103
        return 'menu-chart-hourglass';
104
    }
105
106
    /**
107
     * Return a menu item for this chart - for use in individual boxes.
108
     *
109
     * @param Individual $individual
110
     *
111
     * @return Menu|null
112
     */
113
    public function chartBoxMenu(Individual $individual): ?Menu
114
    {
115
        return $this->chartMenu($individual);
116
    }
117
118
    /**
119
     * The title for a specific instance of this chart.
120
     *
121
     * @param Individual $individual
122
     *
123
     * @return string
124
     */
125
    public function chartTitle(Individual $individual): string
126
    {
127
        /* I18N: %s is an individual’s name */
128
        return I18N::translate('Hourglass chart of %s', $individual->fullName());
129
    }
130
131
    /**
132
     * The URL for a page showing chart options.
133
     *
134
     * @param Individual $individual
135
     * @param string[]   $parameters
136
     *
137
     * @return string
138
     */
139
    public function chartUrl(Individual $individual, array $parameters = []): string
140
    {
141
        return route(self::ROUTE_NAME, [
142
                'xref' => $individual->xref(),
143
                'tree' => $individual->tree()->name(),
144
            ] + $parameters + self::DEFAULT_PARAMETERS);
145
    }
146
147
    /**
148
     * @param ServerRequestInterface $request
149
     *
150
     * @return ResponseInterface
151
     */
152
    public function handle(ServerRequestInterface $request): ResponseInterface
153
    {
154
        $tree        = $request->getAttribute('tree');
155
        $user        = $request->getAttribute('user');
156
        $xref        = $request->getAttribute('xref');
157
        $generations = (int) $request->getAttribute('generations');
158
        $spouses     = (bool) $request->getAttribute('spouses');
159
        $ajax        = $request->getQueryParams()['ajax'] ?? '';
160
        $individual  = Individual::getInstance($xref, $tree);
161
162
        // Convert POST requests into GET requests for pretty URLs.
163
        if ($request->getMethod() === RequestMethodInterface::METHOD_POST) {
164
            return redirect(route(self::ROUTE_NAME, [
165
                'tree'        => $request->getAttribute('tree')->name(),
166
                'xref'        => $request->getParsedBody()['xref'],
167
                'generations' => $request->getParsedBody()['generations'],
168
                'spouses'     => $request->getParsedBody()['spouses'] ?? false,
169
            ]));
170
        }
171
172
        Auth::checkIndividualAccess($individual);
173
        Auth::checkComponentAccess($this, 'chart', $tree, $user);
174
175
        $generations = min($generations, self::MAXIMUM_GENERATIONS);
176
        $generations = max($generations, self::MINIMUM_GENERATIONS);
177
178
        if ($ajax === '1') {
179
            $this->layout = 'layouts/ajax';
180
181
            return $this->viewResponse('modules/hourglass-chart/chart', [
182
                'generations' => $generations,
183
                'individual'  => $individual,
184
                'spouses'     => $spouses,
185
            ]);
186
        }
187
188
        $ajax_url = $this->chartUrl($individual, [
189
            'ajax'        => true,
190
            'generations' => $generations,
191
            'spouses'     => $spouses,
192
        ]);
193
194
        return $this->viewResponse('modules/hourglass-chart/page', [
195
            'ajax_url'            => $ajax_url,
196
            'generations'         => $generations,
197
            'individual'          => $individual,
198
            'maximum_generations' => self::MAXIMUM_GENERATIONS,
199
            'minimum_generations' => self::MINIMUM_GENERATIONS,
200
            'module'              => $this->name(),
201
            'spouses'             => $spouses,
202
            'title'               => $this->chartTitle($individual),
203
        ]);
204
    }
205
206
    /**
207
     * Generate an extension to the chart
208
     *
209
     * @param ServerRequestInterface $request
210
     *
211
     * @return ResponseInterface
212
     */
213
    public function getAncestorsAction(ServerRequestInterface $request): ResponseInterface
214
    {
215
        $tree = $request->getAttribute('tree');
216
        $xref = $request->getQueryParams()['xref'] ?? '';
217
218
        $family = Family::getInstance($xref, $tree);
219
        Auth::checkFamilyAccess($family);
220
221
        return response(view('modules/hourglass-chart/parents', [
222
            'family'      => $family,
223
            'generations' => 1,
224
        ]));
225
    }
226
227
    /**
228
     * Generate an extension to the chart
229
     *
230
     * @param ServerRequestInterface $request
231
     *
232
     * @return ResponseInterface
233
     */
234
    public function getDescendantsAction(ServerRequestInterface $request): ResponseInterface
235
    {
236
        $tree = $request->getAttribute('tree');
237
        $xref = $request->getQueryParams()['xref'] ?? '';
238
239
        $spouses    = (bool) ($request->getQueryParams()['spouses'] ?? false);
240
        $individual = Individual::getInstance($xref, $tree);
241
242
        Auth::checkIndividualAccess($individual);
243
244
        $children = $individual->spouseFamilies()->map(static function (Family $family): Collection {
245
            return $family->children();
246
        })->flatten();
247
248
        return response(view('modules/hourglass-chart/children', [
249
            'children'    => $children,
250
            'generations' => 1,
251
            'spouses'     => $spouses,
252
        ]));
253
    }
254
}
255