Passed
Push — master ( 12c7ed...dbe534 )
by Greg
06:17
created

PlaceHierarchyController::getEvents()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 36
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 30
nc 1
nop 2
dl 0
loc 36
rs 9.44
c 0
b 0
f 0

1 Method

Rating   Name   Duplication   Size   Complexity  
A PlaceHierarchyController::breadcrumbs() 0 19 3
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
18
declare(strict_types=1);
19
20
namespace Fisharebest\Webtrees\Http\Controllers;
21
22
use Exception;
23
use Fisharebest\Webtrees\Exceptions\HttpNotFoundException;
24
use Fisharebest\Webtrees\I18N;
25
use Fisharebest\Webtrees\Location;
26
use Fisharebest\Webtrees\Place;
27
use Fisharebest\Webtrees\Services\SearchService;
28
use Fisharebest\Webtrees\Site;
29
use Fisharebest\Webtrees\Statistics;
30
use Fisharebest\Webtrees\Tree;
31
use Fisharebest\Webtrees\Webtrees;
32
use Psr\Http\Message\ResponseInterface;
33
use Psr\Http\Message\ServerRequestInterface;
34
35
use function array_chunk;
36
use function array_pop;
37
use function array_reverse;
38
use function assert;
39
use function ceil;
40
use function count;
41
use function is_file;
42
use function redirect;
43
use function view;
44
45
/**
46
 * Class PlaceHierarchyController
47
 */
48
class PlaceHierarchyController extends AbstractBaseController
49
{
50
    /** @var SearchService */
51
    private $search_service;
52
53
    /** @var Statistics */
54
    private $statistics;
55
56
    /**
57
     * PlaceHierarchy constructor.
58
     *
59
     * @param SearchService $search_service
60
     * @param Statistics    $statistics
61
     */
62
    public function __construct(SearchService $search_service, Statistics $statistics)
63
    {
64
        $this->search_service = $search_service;
65
        $this->statistics     = $statistics;
66
    }
67
68
    /**
69
     * @param ServerRequestInterface $request
70
     *
71
     * @return ResponseInterface
72
     */
73
    public function show(ServerRequestInterface $request): ResponseInterface
74
    {
75
        $tree = $request->getAttribute('tree');
76
        assert($tree instanceof Tree);
77
78
        $module   = $request->getAttribute('module');
79
        $action   = $request->getAttribute('action');
80
        $action2  = $request->getQueryParams()['action2'] ?? 'hierarchy';
81
        $place_id = (int) ($request->getQueryParams()['place_id'] ?? 0);
82
        $place    = Place::find($place_id, $tree);
83
84
        // Request for a non-existent place?
85
        if ($place_id !== $place->id()) {
86
            return redirect($place->url());
87
        }
88
89
        $content    = '';
90
        $showmap    = Site::getPreference('map-provider') !== '';
91
        $data       = null;
92
93
        if ($showmap) {
94
            $content .= view('modules/place-hierarchy/map', [
95
                'data'     => $this->mapData($place),
96
                'provider' => [
97
                    'name'    => 'OpenStreetMap.Mapnik',
98
                    'options' => []
99
                ]
100
            ]);
101
        }
102
103
        switch ($action2) {
104
            case 'list':
105
                $nextaction = ['hierarchy' => I18N::translate('Show place hierarchy')];
106
                $content .= view('modules/place-hierarchy/list', $this->getList($tree));
107
                break;
108
            case 'hierarchy':
109
            case 'hierarchy-e':
110
                $nextaction = ['list' => I18N::translate('Show all places in a list')];
111
                $data       = $this->getHierarchy($place);
112
                $content .= (null === $data || $showmap) ? '' : view('place-hierarchy', $data);
113
                if (null === $data || $action2 === 'hierarchy-e') {
114
                    $content .= view('modules/place-hierarchy/events', [
115
                        'indilist' => $this->search_service->searchIndividualsInPlace($place),
116
                        'famlist'  => $this->search_service->searchFamiliesInPlace($place),
117
                        'tree'     => $place->tree(),
118
                    ]);
119
                }
120
                break;
121
            default:
122
                throw new HttpNotFoundException('Invalid action');
123
        }
124
125
        $breadcrumbs = $this->breadcrumbs($place);
126
127
        return $this->viewResponse(
128
            'modules/place-hierarchy/page',
129
            [
130
                'title'          => I18N::translate('Places'),
131
                'tree'           => $tree,
132
                'current'        => $breadcrumbs['current'],
133
                'breadcrumbs'    => $breadcrumbs['breadcrumbs'],
134
                'place'          => $place,
135
                'content'        => $content,
136
                'showeventslink' => null !== $data && $place->gedcomName() !== '' && $action2 !== 'hierarchy-e',
137
                'nextaction'     => $nextaction,
138
                'module'         => $module,
139
                'action'         => $action,
140
            ]
141
        );
142
    }
143
144
    /**
145
     * @param Tree $tree
146
     *
147
     * @return Place[][]
148
     */
149
    private function getList(Tree $tree): array
150
    {
151
        $places = $this->search_service->searchPlaces($tree, '')
152
            ->sort(static function (Place $x, Place $y): int {
153
                return $x->gedcomName() <=> $y->gedcomName();
154
            })
155
            ->all();
156
157
        $numfound = count($places);
158
159
        if ($numfound === 0) {
160
            $columns = [];
161
        } else {
162
            $divisor = $numfound > 20 ? 3 : 2;
163
            $columns = array_chunk($places, (int) ceil($numfound / $divisor));
164
        }
165
166
        return [
167
            'columns' => $columns,
168
        ];
169
    }
170
171
172
    /**
173
     * @param Place $place
174
     *
175
     * @return array|null
176
     * @throws Exception
177
     */
178
    private function getHierarchy(Place $place): ?array
179
    {
180
        $child_places = $place->getChildPlaces();
181
        $numfound     = count($child_places);
182
183
        if ($numfound > 0) {
184
            $divisor = $numfound > 20 ? 3 : 2;
185
186
            return
187
                [
188
                    'tree'      => $place->tree(),
189
                    'col_class' => 'w-' . ($divisor === 2 ? '25' : '50'),
190
                    'columns'   => array_chunk($child_places, (int) ceil($numfound / $divisor)),
191
                    'place'     => $place,
192
                ];
193
        }
194
195
        return null;
196
    }
197
198
    /**
199
     * @param Place $place
200
     *
201
     * @return array
202
     */
203
    private function breadcrumbs($place): array
204
    {
205
        $breadcrumbs = [];
206
        if ($place->gedcomName() !== '') {
207
            $breadcrumbs[] = $place;
208
            $parent_place  = $place->parent();
209
            while ($parent_place->gedcomName() !== '') {
210
                $breadcrumbs[] = $parent_place;
211
                $parent_place  = $parent_place->parent();
212
            }
213
            $breadcrumbs = array_reverse($breadcrumbs);
214
            $current     = array_pop($breadcrumbs);
215
        } else {
216
            $current = '';
217
        }
218
219
        return [
220
            'breadcrumbs' => $breadcrumbs,
221
            'current'     => $current,
222
        ];
223
    }
224
225
    /**
226
     * @param Place $placeObj
227
     *
228
     * @return array
229
     */
230
    protected function mapData(Place $placeObj): array
231
    {
232
        $places    = $placeObj->getChildPlaces();
233
        $features  = [];
234
        $sidebar   = '';
235
        $flag_path = Webtrees::MODULES_DIR . 'openstreetmap/';
236
        $show_link = true;
237
238
        if ($places === []) {
239
            $places[] = $placeObj;
240
            $show_link = false;
241
        }
242
243
        foreach ($places as $id => $place) {
244
            $location = new Location($place->gedcomName());
245
246
            if ($location->icon() !== '' && is_file($flag_path . $location->icon())) {
247
                $flag = $flag_path . $location->icon();
248
            } else {
249
                $flag = '';
250
            }
251
252
            if ($location->latitude() === 0.0 && $location->longitude() === 0.0) {
253
                $sidebar_class = 'unmapped';
254
            } else {
255
                $sidebar_class = 'mapped';
256
                $features[]    = [
257
                    'type'       => 'Feature',
258
                    'id'         => $id,
259
                    'geometry'   => [
260
                        'type'        => 'Point',
261
                        'coordinates' => [$location->longitude(), $location->latitude()],
262
                    ],
263
                    'properties' => [
264
                        'tooltip' => $place->gedcomName(),
265
                        'popup'   => view('modules/place-hierarchy/popup', [
266
                            'showlink'  => $show_link,
267
                            'flag'      => $flag,
268
                            'place'     => $place,
269
                            'latitude'  => $location->latitude(),
270
                            'longitude' => $location->longitude(),
271
                        ]),
272
                        'zoom'    => $location->zoom() ?: 2,
273
                    ],
274
                ];
275
            }
276
277
            //Stats
278
            $placeStats = [];
279
            foreach (['INDI', 'FAM'] as $type) {
280
                $tmp               = $this->statistics->statsPlaces($type, '', $place->id());
281
                $placeStats[$type] = $tmp === [] ? 0 : $tmp[0]->tot;
282
            }
283
            $sidebar .= view('modules/place-hierarchy/sidebar', [
284
                'showlink'      => $show_link,
285
                'flag'          => $flag,
286
                'id'            => $id,
287
                'place'         => $place,
288
                'sidebar_class' => $sidebar_class,
289
                'stats'         => $placeStats,
290
            ]);
291
        }
292
293
        return [
294
            'sidebar' => $sidebar,
295
            'markers' => [
296
                'type'     => 'FeatureCollection',
297
                'features' => $features,
298
            ]
299
        ];
300
    }
301
}
302