xref: /webtrees/app/Module/InteractiveTreeModule.php (revision e5a6b4d4f6f6e7ff2fba7ae2cf27546ae68a79cc)
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
205edf1a44SGreg Roachuse Fisharebest\Webtrees\Auth;
21*e5a6b4d4SGreg Roachuse Fisharebest\Webtrees\Contracts\UserInterface;
220bc54ba3SGreg Roachuse Fisharebest\Webtrees\Exceptions\IndividualAccessDeniedException;
230bc54ba3SGreg Roachuse Fisharebest\Webtrees\Exceptions\IndividualNotFoundException;
248d0ebef0SGreg Roachuse Fisharebest\Webtrees\Gedcom;
250e62c4b8SGreg Roachuse Fisharebest\Webtrees\I18N;
260e62c4b8SGreg Roachuse Fisharebest\Webtrees\Individual;
27168ff6f3Sric2016use Fisharebest\Webtrees\Menu;
28e46b0479SScrutinizer Auto-Fixeruse Fisharebest\Webtrees\Module\InteractiveTree\TreeView;
29e2ae4578SGreg Roachuse Fisharebest\Webtrees\Tree;
308d0ebef0SGreg Roachuse Fisharebest\Webtrees\Webtrees;
31e2ae4578SGreg Roachuse Symfony\Component\HttpFoundation\Request;
32e2ae4578SGreg Roachuse Symfony\Component\HttpFoundation\Response;
338c2e8227SGreg Roach
348c2e8227SGreg Roach/**
358c2e8227SGreg Roach * Class InteractiveTreeModule
368c2e8227SGreg Roach * Tip : you could change the number of generations loaded before ajax calls both in individual page and in treeview page to optimize speed and server load
378c2e8227SGreg Roach */
3837eb8894SGreg Roachclass InteractiveTreeModule extends AbstractModule implements ModuleChartInterface, ModuleTabInterface
39c1010edaSGreg Roach{
4049a243cbSGreg Roach    use ModuleChartTrait;
4149a243cbSGreg Roach    use ModuleTabTrait;
4249a243cbSGreg Roach
43961ec755SGreg Roach    /**
44961ec755SGreg Roach     * How should this module be labelled on tabs, menus, etc.?
45961ec755SGreg Roach     *
46961ec755SGreg Roach     * @return string
47961ec755SGreg Roach     */
4849a243cbSGreg Roach    public function title(): string
49c1010edaSGreg Roach    {
50bbb76c12SGreg Roach        /* I18N: Name of a module */
51bbb76c12SGreg Roach        return I18N::translate('Interactive tree');
528c2e8227SGreg Roach    }
538c2e8227SGreg Roach
54961ec755SGreg Roach    /**
55961ec755SGreg Roach     * A sentence describing what this module does.
56961ec755SGreg Roach     *
57961ec755SGreg Roach     * @return string
58961ec755SGreg Roach     */
5949a243cbSGreg Roach    public function description(): string
60c1010edaSGreg Roach    {
61bbb76c12SGreg Roach        /* I18N: Description of the “Interactive tree” module */
62bbb76c12SGreg Roach        return I18N::translate('An interactive tree, showing all the ancestors and descendants of an individual.');
638c2e8227SGreg Roach    }
648c2e8227SGreg Roach
6549a243cbSGreg Roach    /**
6649a243cbSGreg Roach     * The default position for this tab.  It can be changed in the control panel.
6749a243cbSGreg Roach     *
6849a243cbSGreg Roach     * @return int
6949a243cbSGreg Roach     */
70cbf4b7faSGreg Roach    public function defaultTabOrder(): int
71cbf4b7faSGreg Roach    {
72353b36abSGreg Roach        return 9;
738c2e8227SGreg Roach    }
748c2e8227SGreg Roach
758c2e8227SGreg Roach    /** {@inheritdoc} */
769b34404bSGreg Roach    public function getTabContent(Individual $individual): string
77c1010edaSGreg Roach    {
78225e381fSGreg Roach        $treeview = new TreeView('tvTab');
795edf1a44SGreg Roach
8065e02381SGreg Roach        [$html, $js] = $treeview->drawViewport($individual, 3);
818c2e8227SGreg Roach
825edf1a44SGreg Roach        return view('modules/interactive-tree/tab', [
83225e381fSGreg Roach            'html'         => $html,
84225e381fSGreg Roach            'js'           => $js,
85d5691647SGreg Roach            'treeview_css' => $this->css(),
86d5691647SGreg Roach            'treeview_js'  => $this->js(),
87225e381fSGreg Roach        ]);
888c2e8227SGreg Roach    }
898c2e8227SGreg Roach
90d5691647SGreg Roach    /**
91d5691647SGreg Roach     * @return string
92d5691647SGreg Roach     */
93c1010edaSGreg Roach    public function css(): string
94c1010edaSGreg Roach    {
9526684e68SGreg Roach        return Webtrees::MODULES_PATH . $this->name() . '/css/treeview.css';
96d5691647SGreg Roach    }
97d5691647SGreg Roach
98d5691647SGreg Roach    /**
99d5691647SGreg Roach     * @return string
100d5691647SGreg Roach     */
101c1010edaSGreg Roach    public function js(): string
102c1010edaSGreg Roach    {
10326684e68SGreg Roach        return Webtrees::MODULES_PATH . $this->name() . '/js/treeview.js';
104d5691647SGreg Roach    }
105d5691647SGreg Roach
1068c2e8227SGreg Roach    /** {@inheritdoc} */
1079b34404bSGreg Roach    public function hasTabContent(Individual $individual): bool
108c1010edaSGreg Roach    {
10915d603e7SGreg Roach        return true;
1108c2e8227SGreg Roach    }
1118c2e8227SGreg Roach
1128c2e8227SGreg Roach    /** {@inheritdoc} */
1139b34404bSGreg Roach    public function isGrayedOut(Individual $individual): bool
114c1010edaSGreg Roach    {
1158c2e8227SGreg Roach        return false;
1168c2e8227SGreg Roach    }
1178c2e8227SGreg Roach
1188c2e8227SGreg Roach    /** {@inheritdoc} */
1199b34404bSGreg Roach    public function canLoadAjax(): bool
120c1010edaSGreg Roach    {
1218c2e8227SGreg Roach        return true;
1228c2e8227SGreg Roach    }
1238c2e8227SGreg Roach
124168ff6f3Sric2016    /**
125377a2979SGreg Roach     * CSS class for the URL.
126377a2979SGreg Roach     *
127377a2979SGreg Roach     * @return string
128377a2979SGreg Roach     */
129377a2979SGreg Roach    public function chartMenuClass(): string
130377a2979SGreg Roach    {
131377a2979SGreg Roach        return 'menu-chart-tree';
132377a2979SGreg Roach    }
133377a2979SGreg Roach
134377a2979SGreg Roach    /**
1354eb71cfaSGreg Roach     * Return a menu item for this chart - for use in individual boxes.
1364eb71cfaSGreg Roach     *
13760bc3e3fSGreg Roach     * @param Individual $individual
13860bc3e3fSGreg Roach     *
1394eb71cfaSGreg Roach     * @return Menu|null
1404eb71cfaSGreg Roach     */
141377a2979SGreg Roach    public function chartBoxMenu(Individual $individual): ?Menu
142c1010edaSGreg Roach    {
143e6562982SGreg Roach        return $this->chartMenu($individual);
144e6562982SGreg Roach    }
145e6562982SGreg Roach
146e6562982SGreg Roach    /**
147e6562982SGreg Roach     * The title for a specific instance of this chart.
148e6562982SGreg Roach     *
149e6562982SGreg Roach     * @param Individual $individual
150e6562982SGreg Roach     *
151e6562982SGreg Roach     * @return string
152e6562982SGreg Roach     */
153e6562982SGreg Roach    public function chartTitle(Individual $individual): string
154e6562982SGreg Roach    {
155e6562982SGreg Roach        /* I18N: %s is an individual’s name */
156e6562982SGreg Roach        return I18N::translate('Interactive tree of %s', $individual->getFullName());
157e6562982SGreg Roach    }
158e6562982SGreg Roach
159e6562982SGreg Roach    /**
160e6562982SGreg Roach     * The URL for this chart.
161e6562982SGreg Roach     *
162e6562982SGreg Roach     * @param Individual $individual
163e6562982SGreg Roach     * @param string[]   $parameters
164e6562982SGreg Roach     *
165e6562982SGreg Roach     * @return string
166e6562982SGreg Roach     */
167e6562982SGreg Roach    public function chartUrl(Individual $individual, array $parameters = []): string
168e6562982SGreg Roach    {
169e6562982SGreg Roach        return route('module', [
17026684e68SGreg Roach                'module' => $this->name(),
1715edf1a44SGreg Roach                'action' => 'Chart',
172e6562982SGreg Roach                'xref'   => $individual->xref(),
173e6562982SGreg Roach                'ged'    => $individual->tree()->name(),
174e6562982SGreg Roach            ] + $parameters);
175e6562982SGreg Roach    }
176e6562982SGreg Roach
177e6562982SGreg Roach    /**
178e2ae4578SGreg Roach     * @param Request       $request
179b6db7c1fSGreg Roach     * @param Tree          $tree
180*e5a6b4d4SGreg Roach     * @param UserInterface $user
18176692c8bSGreg Roach     *
182e2ae4578SGreg Roach     * @return Response
18376692c8bSGreg Roach     */
184*e5a6b4d4SGreg Roach    public function getChartAction(Request $request, Tree $tree, UserInterface $user): Response
185c1010edaSGreg Roach    {
1869e648e55SGreg Roach        $xref = $request->get('xref', '');
187e2ae4578SGreg Roach
188e2ae4578SGreg Roach        $individual = Individual::getInstance($xref, $tree);
189bfaf8159SGreg Roach
1905edf1a44SGreg Roach        Auth::checkIndividualAccess($individual);
1919867b2f0SGreg Roach        Auth::checkComponentAccess($this, 'chart', $tree, $user);
192bfaf8159SGreg Roach
1938c2e8227SGreg Roach        $tv = new TreeView('tv');
1948c2e8227SGreg Roach
19565e02381SGreg Roach        [$html, $js] = $tv->drawViewport($individual, 4);
1968c2e8227SGreg Roach
197e2ae4578SGreg Roach        return $this->viewResponse('interactive-tree-page', [
1985edf1a44SGreg Roach            'html'       => $html,
1998840c547SGreg Roach            'individual' => $individual,
200e2ae4578SGreg Roach            'js'         => $js,
2015edf1a44SGreg Roach            'title'      => $this->chartTitle($individual),
202e2ae4578SGreg Roach            'tree'       => $tree,
203f8a18b14SGreg Roach        ]);
2048c2e8227SGreg Roach    }
2058c2e8227SGreg Roach
206e2ae4578SGreg Roach    /**
207e2ae4578SGreg Roach     * @param Request $request
208b6db7c1fSGreg Roach     * @param Tree    $tree
209e2ae4578SGreg Roach     *
210e2ae4578SGreg Roach     * @return Response
211e2ae4578SGreg Roach     */
212b6db7c1fSGreg Roach    public function getDetailsAction(Request $request, Tree $tree): Response
213c1010edaSGreg Roach    {
2148d0ebef0SGreg Roach        $pid        = $request->get('pid', Gedcom::REGEX_XREF);
215e2ae4578SGreg Roach        $individual = Individual::getInstance($pid, $tree);
216e2ae4578SGreg Roach
2170bc54ba3SGreg Roach        if ($individual === null) {
21859f2f229SGreg Roach            throw new IndividualNotFoundException();
2190bc54ba3SGreg Roach        }
2200bc54ba3SGreg Roach
2210bc54ba3SGreg Roach        if (!$individual->canShow()) {
22259f2f229SGreg Roach            throw new IndividualAccessDeniedException();
2230bc54ba3SGreg Roach        }
2240bc54ba3SGreg Roach
2259e648e55SGreg Roach        $instance = $request->get('instance', '');
226e2ae4578SGreg Roach        $treeview = new TreeView($instance);
227e2ae4578SGreg Roach
228e2ae4578SGreg Roach        return new Response($treeview->getDetails($individual));
2298c2e8227SGreg Roach    }
2308c2e8227SGreg Roach
2318c2e8227SGreg Roach    /**
232e2ae4578SGreg Roach     * @param Request $request
233b6db7c1fSGreg Roach     * @param Tree    $tree
2343cf92ae2SGreg Roach     *
235e2ae4578SGreg Roach     * @return Response
2368c2e8227SGreg Roach     */
237b6db7c1fSGreg Roach    public function getPersonsAction(Request $request, Tree $tree): Response
238c1010edaSGreg Roach    {
2399e648e55SGreg Roach        $q        = $request->get('q', '');
2409e648e55SGreg Roach        $instance = $request->get('instance', '');
241e2ae4578SGreg Roach        $treeview = new TreeView($instance);
2428c2e8227SGreg Roach
243bc8b8f24SGreg Roach        return new Response($treeview->getPersons($tree, $q));
2448c2e8227SGreg Roach    }
2458c2e8227SGreg Roach}
246