Migration2::mappingPropertyForMap()   A
last analyzed

Complexity

Conditions 5
Paths 5

Size

Total Lines 12
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 10
nc 5
nop 1
dl 0
loc 12
rs 9.6111
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * webtrees-lib: MyArtJaub library for webtrees
5
 *
6
 * @package MyArtJaub\Webtrees
7
 * @subpackage GeoDispersion
8
 * @author Jonathan Jaubart <[email protected]>
9
 * @copyright Copyright (c) 2009-2022, Jonathan Jaubart
10
 * @license http://www.gnu.org/licenses/gpl.html GNU General Public License, version 3
11
 */
12
13
declare(strict_types=1);
14
15
namespace MyArtJaub\Webtrees\Module\GeoDispersion\Schema;
16
17
use Fisharebest\Webtrees\FlashMessages;
18
use Fisharebest\Webtrees\I18N;
19
use Fisharebest\Webtrees\Tree;
20
use Fisharebest\Webtrees\Schema\MigrationInterface;
21
use Fisharebest\Webtrees\Services\TreeService;
22
use Illuminate\Database\Capsule\Manager as DB;
23
use MyArtJaub\Webtrees\Common\GeoDispersion\Config\MapColorsConfig;
24
use MyArtJaub\Webtrees\Common\GeoDispersion\Config\MapViewConfig;
25
use MyArtJaub\Webtrees\Module\GeoDispersion\Model\GeoAnalysisMapAdapter;
26
use MyArtJaub\Webtrees\Module\GeoDispersion\PlaceMappers\SimplePlaceMapper;
27
use MyArtJaub\Webtrees\Module\GeoDispersion\Services\GeoAnalysisViewDataService;
28
use MyArtJaub\Webtrees\Module\GeoDispersion\Services\MapAdapterDataService;
29
use MyArtJaub\Webtrees\Module\GeoDispersion\Services\MapDefinitionsService;
30
use MyArtJaub\Webtrees\Module\GeoDispersion\Views\GeoAnalysisMap;
31
use MyArtJaub\Webtrees\Module\GeoDispersion\Views\GeoAnalysisTable;
32
use MyArtJaub\Webtrees\Module\Sosa\GeoAnalyses\SosaByGenerationGeoAnalysis;
33
use Spatie\Color\Hex;
34
use RuntimeException;
35
use stdClass;
36
37
/**
38
 * Upgrade the database schema from version 2 to version 3 (migrated views from webtrees 1.7).
39
 */
40
class Migration2 implements MigrationInterface
41
{
42
    /**
43
     * Mapping from old map definitions to new ones
44
     * @var array<string,mixed> MAPS_XML_MAPPING
45
     */
46
    private const MAPS_XML_MAPPING = [
47
        'aubracmargeridebycommunes.xml' =>  'fr-area-aubrac-lot-margeride-planeze-communes',
48
        'calvadosbycommunes.xml'        =>  'fr-dpt-14-communes',
49
        'cantalbycommunes.xml'          =>  'fr-dpt-15-communes',
50
        'cotesdarmorbycommunes.xml'     =>  'fr-dpt-22-communes',
51
        'essonnebycommunes.xml'         =>  'fr-dpt-91-communes',
52
        'eurebycommunes.xml'            =>  'fr-dpt-27-communes',
53
        'eureetloirbycommunes.xml'      =>  'fr-dpt-28-communes',
54
        'francebydepartements.xml'      =>  'fr-metropole-departements',
55
        'francebyregions1970.xml'       =>  'fr-metropole-regions-1970',
56
        'francebyregions2016.xml'       =>  'fr-metropole-regions-2016',
57
        'hauteloirebycommunes.xml'      =>  'fr-dpt-43-communes',
58
        'illeetvilainebycommunes.xml'   =>  'fr-dpt-35-communes',
59
        'loiretbycommunes.xml'          =>  'fr-dpt-45-communes',
60
        'lozerebycodepostaux.xml'       =>  'fr-dpt-48-codespostaux',
61
        'lozerebycommunes.xml'          =>  'fr-dpt-48-communes',
62
        'mayennebycommunes.xml'         =>  'fr-dpt-53-communes',
63
        'oisebycommunes.xml'            =>  'fr-dpt-60-communes',
64
        'ornebycommunes.xml'            =>  'fr-dpt-61-communes',
65
        'puydedomebycommunes.xml'       =>  'fr-dpt-63-communes',
66
        'sarthebycommunes.xml'          =>  'fr-dpt-72-communes',
67
        'seinemaritimebycommunes.xml'   =>  'fr-dpt-76-communes',
68
        'seinesommeoisebycommunes.xml'  =>  ['fr-dpt-60-communes', 'fr-dpt-76-communes', 'fr-dpt-80-communes'],
69
        'valdoisebycommunes.xml'        =>  'fr-dpt-95-communes',
70
        'yvelinesbycommunes.xml'        =>  'fr-dpt-78-communes'
71
    ];
72
73
    /**
74
     * {@inheritDoc}
75
     * @see \Fisharebest\Webtrees\Schema\MigrationInterface::upgrade()
76
     */
77
    public function upgrade(): void
78
    {
79
        if (!DB::schema()->hasTable('maj_geodispersion')) {
80
            return;
81
        }
82
83
        /** @var TreeService $tree_service */
84
        $tree_service = app(TreeService::class);
85
        /** @var GeoAnalysisViewDataService $geoview_data_service */
86
        $geoview_data_service = app(GeoAnalysisViewDataService::class);
87
88
        $existing_views = DB::table('maj_geodispersion')
89
            ->select()
90
            ->get();
91
92
        foreach ($existing_views as $old_view) {
93
            try {
94
                $tree = $tree_service->find((int) $old_view->majgd_file);
95
            } catch (RuntimeException $ex) {
96
                continue;
97
            }
98
99
            if ($old_view->majgd_map === null) {
100
                $this->migrateGeoAnalysisTable($old_view, $tree, $geoview_data_service);
101
            } else {
102
                DB::connection()->beginTransaction();
103
                if ($this->migrateGeoAnalysisMap($old_view, $tree, $geoview_data_service)) {
104
                    DB::connection()->commit();
105
                } else {
106
                    DB::connection()->rollBack();
107
                }
108
            }
109
        }
110
111
        $in_transaction = DB::connection()->getPdo()->inTransaction();
112
113
        DB::schema()->drop('maj_geodispersion');
114
115
        if ($in_transaction && !DB::connection()->getPdo()->inTransaction()) {
116
            DB::connection()->beginTransaction();
117
        }
118
119
        FlashMessages::addMessage(I18N::translate(
120
            'The geographical dispersion analyses have been migrated for webtrees 2. Please review their settings.'
121
        ));
122
    }
123
124
    /**
125
     * Create a Table geographical analysis view from a migrated item.
126
     *
127
     * @param stdClass $old_view
128
     * @param Tree $tree
129
     * @param GeoAnalysisViewDataService $geoview_data_service
130
     * @return bool
131
     */
132
    private function migrateGeoAnalysisTable(
133
        stdClass $old_view,
134
        Tree $tree,
135
        GeoAnalysisViewDataService $geoview_data_service
136
    ): bool {
137
        $new_view = new GeoAnalysisTable(
138
            0,
139
            $tree,
140
            $old_view->majgd_status === 'enabled',
141
            $old_view->majgd_descr,
142
            app(SosaByGenerationGeoAnalysis::class),
143
            (int) $old_view->majgd_sublevel,
144
            (int) $old_view->majgd_detailsgen
145
        );
146
147
        return $geoview_data_service->insertGetId($new_view) > 0;
148
    }
149
150
    /**
151
     * Create a Map geographical analysis view from a migrated item.
152
     *
153
     * @param stdClass $old_view
154
     * @param Tree $tree
155
     * @param GeoAnalysisViewDataService $geoview_data_service
156
     * @return bool
157
     */
158
    private function migrateGeoAnalysisMap(
159
        stdClass $old_view,
160
        Tree $tree,
161
        GeoAnalysisViewDataService $geoview_data_service
162
    ): bool {
163
        /** @var MapDefinitionsService $map_definition_service */
164
        $map_definition_service = app(MapDefinitionsService::class);
165
        /** @var MapAdapterDataService $mapadapter_data_service */
166
        $mapadapter_data_service = app(MapAdapterDataService::class);
167
168
        $new_view = new GeoAnalysisMap(
169
            0,
170
            $tree,
171
            $old_view->majgd_status === 'enabled',
172
            $old_view->majgd_descr,
173
            app(SosaByGenerationGeoAnalysis::class),
174
            (int) $old_view->majgd_sublevel,
175
            (int) $old_view->majgd_detailsgen
176
        );
177
178
        $view_id = $geoview_data_service->insertGetId($new_view);
179
        if ($view_id === 0) {
180
            return false;
181
        }
182
        $new_view = $new_view->withId($view_id);
183
184
        $colors = $new_view->colors();
185
        foreach ($this->mapIdsFromOld($old_view->majgd_map) as $new_map_id) {
186
            $map = $map_definition_service->find($new_map_id);
187
            if ($map === null) {
188
                return false;
189
            }
190
            $colors = $this->colorsFromMap($new_map_id);
191
192
            /** @var SimplePlaceMapper $mapper */
193
            $mapper = app(SimplePlaceMapper::class);
194
            $mapview_config = new MapViewConfig($this->mappingPropertyForMap($new_map_id), $mapper->config());
195
            $map_adapter = new GeoAnalysisMapAdapter(0, $view_id, $map, $mapper, $mapview_config);
196
197
            $mapadapter_data_service->insertGetId($map_adapter);
198
        }
199
200
        return $geoview_data_service->update($new_view->withColors($colors)) > 0;
201
    }
202
203
    /**
204
     * Get all new map definitions IDs representing an old map definition
205
     *
206
     * @param string $map_xml
207
     * @return string[]
208
     */
209
    private function mapIdsFromOld(string $map_xml): array
210
    {
211
        $mapping = self::MAPS_XML_MAPPING[$map_xml] ?? [];
212
        return is_array($mapping) ? $mapping : [ $mapping ];
213
    }
214
215
    /**
216
     * Get the mapping property to be used for the migrated map adapter
217
     *
218
     * @param string $map_id
219
     * @return string
220
     */
221
    private function mappingPropertyForMap(string $map_id): string
222
    {
223
        switch ($map_id) {
224
            case 'fr-metropole-regions-1970':
225
            case 'fr-metropole-regions-2016':
226
                return 'region_insee_libelle';
227
            case 'fr-metropole-departements':
228
                return 'dpt_insee_libelle';
229
            case 'fr-dpt-48-codespostaux':
230
                return 'code_postal';
231
            default:
232
                return 'commune_insee_libelle';
233
        }
234
    }
235
236
    /**
237
     * Get the color configuration to be used for the migrated map view
238
     *
239
     * @param string $map_id
240
     * @return MapColorsConfig
241
     */
242
    private function colorsFromMap(string $map_id): MapColorsConfig
243
    {
244
        $default = Hex::fromString('#f5f5f5');
245
        $stroke = Hex::fromString('#d5d5d5');
246
        $hover = Hex::fromString('#ff6600');
247
248
        switch ($map_id) {
249
            case 'fr-metropole-departements':
250
                return new MapColorsConfig($default, $stroke, Hex::fromString('#0493ab'), $hover);
251
            case 'fr-dpt-48-codespostaux':
252
                return new MapColorsConfig($default, $stroke, Hex::fromString('#44aa00'), $hover);
253
            default:
254
                return new MapColorsConfig($default, $stroke, Hex::fromString('#e2a61d'), $hover);
255
        }
256
    }
257
}
258