SimpleFrancePlaceMapper::config()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
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) 2021-2023, 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\GeoData\France\PlaceMappers;
16
17
use Fisharebest\Webtrees\I18N;
18
use Fisharebest\Webtrees\Place;
19
use Fisharebest\Webtrees\Registry;
20
use Fisharebest\Webtrees\Services\ModuleService;
21
use MyArtJaub\Webtrees\Common\GeoDispersion\Config\NullPlaceMapperConfig;
22
use MyArtJaub\Webtrees\Contracts\GeoDispersion\MapDefinitionInterface;
23
use MyArtJaub\Webtrees\Contracts\GeoDispersion\PlaceMapperConfigInterface;
24
use MyArtJaub\Webtrees\Contracts\GeoDispersion\PlaceMapperInterface;
25
use MyArtJaub\Webtrees\Module\GeoData\France\GeoDataFranceModule;
26
27
/**
28
 * Enhanced Simple Place Mapper, specific for France places usage.
29
 * It allows for known mappings to override the standard lowest level name, depending on the loaded map.
30
 */
31
class SimpleFrancePlaceMapper implements PlaceMapperInterface
32
{
33
    /**
34
     * Mappings to link regions pre-2016 to the new regions
35
     *
36
     * @var array<string, string>
37
     */
38
    private const MAPPINGS_REGIONS = [
39
        'Auvergne'              =>  'Auvergne-Rhône-Alpes',
40
        'Rhône-Alpes'           =>  'Auvergne-Rhône-Alpes',
41
        'Bourgogne'             =>  'Bourgogne-Franche-Comté',
42
        'Franche-Comté'         =>  'Bourgogne-Franche-Comté',
43
        'Alsace'                =>  'Grand Est',
44
        'Centre'                =>  'Centre-Val de Loire',
45
        'Champagne-Ardenne'     =>  'Grand Est',
46
        'Lorraine'              =>  'Grand Est',
47
        'Nord-Pas-de-Calais'    =>  'Hauts-de-France',
48
        'Picardie'              =>  'Hauts-de-France',
49
        'Ile-de-France'         =>  'Île-de-France',
50
        'Languedoc-Roussillon'  =>  'Occitanie',
51
        'Midi-Pyrénées'         =>  'Occitanie',
52
        'Basse-Normandie'       =>  'Normandie',
53
        'Haute-Normandie'       =>  'Normandie',
54
        'Aquitaine'             =>  'Nouvelle-Aquitaine',
55
        'Limousin'              =>  'Nouvelle-Aquitaine',
56
        'Poitou-Charentes'      =>  'Nouvelle-Aquitaine',
57
    ];
58
59
    /**
60
     * Mappings to link previous names of departements to new ones
61
     *
62
     * @var array<string, string>
63
     */
64
    private const MAPPINGS_DEPARTEMENTS = [
65
        'Basses-Alpes'          =>  'Alpes-de-Haute-Provence',
66
        'Basses-Pyrénées'       =>  'Pyrénées-Atlantiques',
67
        'Charente-Inférieure'   =>  'Charente-Maritime',
68
        'Côtes-du-Nord'         =>  'Côtes-d\'Armor',
69
        'Loire-Inférieure'      =>  'Loire-Atlantique',
70
        'Seine-Inférieure'      =>  'Seine-Maritime',
71
    ];
72
73
    /**
74
     * Miscellaneous known mappings for communes
75
     *
76
     * @var array<string, string>
77
     */
78
    private const MAPPINGS_KNOWN_COMMUNES_VARIATIONS = [
79
        'Sarrus (Fridefont)'                            =>  'Fridefont',
80
        'Magnac (Fridefont)'                            =>  'Fridefont',
81
        'Mallet (Fridefont)'                            =>  'Fridefont',
82
        'Le Bacon (Les Monts-Verts)'                    =>  'Les Monts-Verts',
83
        'Arcomie (Les Monts-Verts)'                     =>  'Les Monts-Verts',
84
        'Anterrieux (Saint-Juéry)'                      =>  'Saint-Juéry',
85
        'Saint-Chély-Forain (Saint-Chély-d\'Apcher)'    =>  'Saint-Chély-d\'Apcher',
86
    ];
87
88
    /**
89
     * @var array<string, mixed>
90
     */
91
    private array $data = [];
92
93
    /**
94
     * {@inheritDoc}
95
     * @see \MyArtJaub\Webtrees\Contracts\GeoDispersion\PlaceMapperInterface::title()
96
     */
97
    public function title(): string
98
    {
99
        return I18N::translate('Mapping on place name, with known variations in France');
100
    }
101
102
    /**
103
     * {@inheritDoc}
104
     * @see \MyArtJaub\Webtrees\Contracts\GeoDispersion\PlaceMapperInterface::data()
105
     */
106
    public function data(string $key)
107
    {
108
        return $this->data[$key] ?? null;
109
    }
110
111
    /**
112
     * {@inheritDoc}
113
     * @see \MyArtJaub\Webtrees\Contracts\GeoDispersion\PlaceMapperInterface::setData()
114
     */
115
    public function setData(string $key, $data): void
116
    {
117
        $this->data[$key] = $data;
118
    }
119
120
    /**
121
     * {@inheritDoc}
122
     * @see \MyArtJaub\Webtrees\Contracts\GeoDispersion\PlaceMapperInterface::boot()
123
     */
124
    public function boot(): void
125
    {
126
    }
127
128
    /**
129
     * {@inheritDoc}
130
     * @see \MyArtJaub\Webtrees\Contracts\GeoDispersion\PlaceMapperInterface::config()
131
     */
132
    public function config(): PlaceMapperConfigInterface
133
    {
134
        return new NullPlaceMapperConfig();
135
    }
136
137
    /**
138
     * {@inheritDoc}
139
     * @see \MyArtJaub\Webtrees\Contracts\GeoDispersion\PlaceMapperInterface::setConfig()
140
     */
141
    public function setConfig(PlaceMapperConfigInterface $config): void
142
    {
143
    }
144
145
    /**
146
     * {@inheritDoc}
147
     * @see \MyArtJaub\Webtrees\Contracts\GeoDispersion\PlaceMapperInterface::map()
148
     */
149
    public function map(Place $place, string $feature_property): ?string
150
    {
151
        $map_def = $this->data('map');
152
        if ($map_def === null || !($map_def instanceof MapDefinitionInterface)) {
153
            return null;
154
        }
155
        $place_mappings = Registry::cache()->array()->remember(
156
            SimpleFrancePlaceMapper::class . '-mapping-' . $map_def->id(),
157
            fn(): array => $this->mappingsForMap($map_def->id())
158
        );
159
160
        $place_name = $place->firstParts(1)->first();
161
        return $place_mappings[$place_name] ?? $place_name;
162
    }
163
164
    /**
165
     * Check whether a string ($haystack) ends with another string ($needle)
166
     *
167
     * {@internal This is redundant with the function str_ends_with in PHP8}
168
     *
169
     * @param string $haystack
170
     * @param string $needle
171
     * @return bool
172
     */
173
    private function endsWith(string $haystack, string $needle): bool
174
    {
175
        return substr_compare($haystack, $needle, -strlen($needle)) === 0;
176
    }
177
178
    /**
179
     * Return the mappings to be used for a specific map
180
     *
181
     * @param string $map_id
182
     * @return array<string, string>
183
     */
184
    private function mappingsForMap(string $map_id): array
185
    {
186
        $mapping = [];
187
        if ($this->endsWith($map_id, '-departements')) {
188
            return self::MAPPINGS_DEPARTEMENTS;
189
        }
190
191
        if ($map_id === 'fr-metropole-regions-2016') {
192
            return self::MAPPINGS_REGIONS;
193
        }
194
195
        if (mb_strpos($map_id, '-communes') !== false) {
196
            $mapping = self::MAPPINGS_KNOWN_COMMUNES_VARIATIONS;
197
        }
198
199
        if ($this->endsWith($map_id, '-communes')) {
200
            $module = app(ModuleService::class)->findByInterface(GeoDataFranceModule::class)->first();
201
            if ($module === null) {
202
                return $mapping;
203
            }
204
205
            $file = $module->resourcesFolder() . '/mappings/new-communes.php';
206
            if (!is_file($file)) {
207
                return $mapping;
208
            }
209
            $mappings_new_communes = include $file;
210
            if (!is_array($mappings_new_communes)) {
211
                return $mapping;
212
            }
213
214
            if (preg_match('/fr-dpt-(\d{2})-communes/', $map_id, $dept_match) === 1) {
215
                return array_merge($mapping, $mappings_new_communes[$dept_match[1]] ?? []);
216
            }
217
218
            if ($map_id === 'fr-area-aubrac-lot-margeride-planeze-communes') {
219
                return array_merge(
220
                    $mapping,
221
                    $mappings_new_communes['12'] ?? [],
222
                    $mappings_new_communes['15'] ?? [],
223
                    $mappings_new_communes['43'] ?? [],
224
                    $mappings_new_communes['48'] ?? [],
225
                );
226
            }
227
        }
228
        return $mapping;
229
    }
230
}
231