Passed
Push — master ( d82780...94e359 )
by Greg
06:13
created

MapDataService::findById()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 12
c 1
b 0
f 0
nc 3
nop 1
dl 0
loc 19
rs 9.8666
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\Services;
21
22
use Fisharebest\Webtrees\Gedcom;
23
use Fisharebest\Webtrees\PlaceLocation;
24
use Illuminate\Database\Capsule\Manager as DB;
25
use stdClass;
26
27
use function array_unshift;
28
29
/**
30
 * Process geographic data.
31
 */
32
class MapDataService
33
{
34
    /**
35
     * @param int $id
36
     *
37
     * @return PlaceLocation
38
     */
39
    public function findById(int $id): PlaceLocation
40
    {
41
        $hierarchy = [];
42
43
        while ($id !== 0) {
44
            $row = DB::table('placelocation')
45
                ->where('pl_id', '=', $id)
46
                ->select(['pl_place', 'pl_parent_id'])
47
                ->first();
48
49
            if ($row === null) {
50
                $id = 0;
51
            } else {
52
                $hierarchy[] = $row->pl_place;
53
                $id          = (int) $row->pl_parent_id;
54
            }
55
        }
56
57
        return new PlaceLocation(implode(Gedcom::PLACE_SEPARATOR, $hierarchy));
58
    }
59
60
    /**
61
     * Which trees use a particular location?
62
     *
63
     * @param PlaceLocation $location
64
     *
65
     * @return array<string,array<stdClass>>
66
     */
67
    public function activePlaces(PlaceLocation $location): array
68
    {
69
        $parents  = $this->placeIdsForLocation($location);
70
        $children = [];
71
72
        $rows = DB::table('places')
73
            ->join('gedcom', 'gedcom.gedcom_id', '=', 'p_file')
74
            ->join('gedcom_setting', 'gedcom_setting.gedcom_id', '=', 'gedcom.gedcom_id')
75
            ->where('setting_name', '=', 'title')
76
            ->whereIn('p_parent_id', $parents)
77
            ->select(['p_place', 'gedcom_name AS tree_name', 'setting_value AS tree_title', 'p_id'])
78
            ->get();
79
80
        foreach ($rows as $row) {
81
            $children[$row->p_place][] = $row;
82
        }
83
84
        return $children;
85
    }
86
87
    /**
88
     * Make sure that all places in the genealogy data also exist in the location data.
89
     *
90
     * @param PlaceLocation $location
91
     *
92
     * @return void
93
     */
94
    public function importMissingChildren(PlaceLocation $location): void
95
    {
96
        $parents = $this->placeIdsForLocation($location);
97
98
        $rows = DB::table('places')
99
            ->join('gedcom', 'gedcom.gedcom_id', '=', 'p_file')
100
            ->whereIn('p_parent_id', $parents)
101
            ->whereNotIn('p_place', static function ($query) use ($location): void {
102
                $query->select(['pl_place'])->from('placelocation')->where('pl_parent_id', '=', $location->id());
103
            })
104
            ->groupBy(['p_place'])
105
            ->select(['p_place'])
106
            ->get();
107
108
        if ($rows->isNotEmpty()) {
109
            $tmp   = clone $location;
110
            $level = 1;
111
112
            while ($tmp->id() !== 0) {
113
                $level++;
114
                $tmp = $tmp->parent();
115
            }
116
117
            foreach ($rows as $row) {
118
                $place_id = 1 + (int) DB::table('placelocation')->max('pl_id');
119
120
                DB::table('placelocation')->insert([
121
                    'pl_id'        => $place_id,
122
                    'pl_parent_id' => $location->id(),
123
                    'pl_level'     => $level,
124
                    'pl_place'     => $row->p_place,
125
                    'pl_lati'      => '',
126
                    'pl_long'      => '',
127
                    'pl_zoom'      => 2,
128
                    'pl_icon'      => '',
129
                ]);
130
            }
131
        }
132
    }
133
134
    /**
135
     * Find all active places that match a location
136
     *
137
     * @param PlaceLocation $location
138
     *
139
     * @return array<string>
140
     */
141
    private function placeIdsForLocation(PlaceLocation $location): array
142
    {
143
        $hierarchy = [];
144
145
        while ($location->id() !== 0) {
146
            array_unshift($hierarchy, $location->locationName());
147
            $location = $location->parent();
148
        }
149
150
        $place_ids = ['0'];
151
152
        foreach ($hierarchy as $place_name) {
153
            $place_ids = DB::table('places')
154
                ->whereIn('p_parent_id', $place_ids)
155
                ->where('p_place', '=', $place_name)
156
                ->groupBy(['p_id'])
157
                ->pluck('p_id')
158
                ->all();
159
        }
160
161
        return $place_ids;
162
    }
163
164
    /**
165
     * @param int $location_id
166
     */
167
    public function deleteRecursively(int $location_id): void
168
    {
169
        $child_ids = DB::table('placelocation')
170
            ->where('pl_parent_id', '=', $location_id)
171
            ->pluck('pl_id');
172
173
        foreach ($child_ids as $child_id) {
174
            $this->deleteRecursively((int) $child_id);
175
        }
176
177
        DB::table('placelocation')
178
            ->where('pl_id', '=', $location_id)
179
            ->delete();
180
    }
181
}
182