Passed
Branch feature/2.1-geodispersion-dev (1d61a8)
by Jonathan
61:21
created

PlacesReferenceTableService::targetId()   B

Complexity

Conditions 6
Paths 7

Size

Total Lines 43
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 27
c 1
b 0
f 0
nc 7
nop 3
dl 0
loc 43
rs 8.8657
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, 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\Services;
16
17
use Illuminate\Database\Capsule\Manager as DB;
18
19
/**
20
 * Service for accessing data in the Places Mapping Reference Table.
21
 */
22
class PlacesReferenceTableService
23
{
24
    /**
25
     * Mapping format placeholder tags => table column names
26
     * @var array<string, string>
27
     */
28
    private const COLUMN_MAPPING = [
29
        'name'  =>  'majgr_place_name',
30
        'id'    =>  'majgr_place_admin_id',
31
        'zip'   =>  'majgr_place_zip',
32
        'gov'   =>  'majgr_place_gov_id',
33
        'mls'   =>  'majgr_place_mls_id'
34
    ];
35
36
    /**
37
     * Get the formatted target mapping value of a place defined by a source format.
38
     *
39
     * @param string $source
40
     * @param string $source_format
41
     * @param string $target_format
42
     * @return string|NULL
43
     */
44
    public function targetId(string $source, string $source_format, string $target_format): ?string
45
    {
46
        // Extract parts for the WHERE clause
47
        $source_format = str_replace(['{', '}'], ['{#', '#}'], $source_format);
48
        $source_parts = preg_split('/[{}]/i', $source_format);
49
        if ($source_parts === false) {
50
            return null;
51
        }
52
        $source_parts = array_map(function (string $part): string {
53
            if (preg_match('/^#([^#]+)#$/i', $part, $column_id) === 1) {
54
                return $this->columnName($column_id[1]);
55
            }
56
            return $this->sanitizeString(str_replace(['?', '*'], ['_', '%'], $part));
57
        }, array_filter($source_parts));
58
        $source_parts[] = "'%'";
59
        $concat_statement = 'CONCAT(' . implode(', ', $source_parts) . ')';
60
61
        // Extract columns used in target
62
        $columns = [];
63
        if (preg_match_all('/{(.*?)}/i', $target_format, $columns_select) === 1) {
64
            $columns = array_unique(array_filter(array_map(fn($id) => $this->columnName($id), $columns_select[1])));
65
        }
66
67
        // Get the mapping
68
        $rows = DB::table('maj_geodata_ref')  //DB::table('maj_geodata_ref')
69
            ->select($columns)
70
            ->whereRaw($this->sanitizeString($source) . " LIKE " . $concat_statement)
71
            ->get();
72
73
        // Format the output ID
74
        if ($rows->count() === 0) {
75
            return null;
76
        }
77
78
        $mapping = (array) $rows->first();
79
        if (count($columns_select) === 0) {
80
            return $target_format;
81
        }
82
83
        return str_replace(
84
            array_map(fn($tag) => '{' . $tag . '}', $columns_select[1]),
85
            array_map(fn($tag) => $mapping[$this->columnName($tag)] ?? '', $columns_select[1]),
86
            $target_format
87
        );
88
    }
89
90
    /**
91
     * Get the column name for a format placeholder tag
92
     *
93
     * @param string $placeholder
94
     * @return string
95
     */
96
    private function columnName(string $placeholder): string
97
    {
98
        return self::COLUMN_MAPPING[$placeholder] ?? '';
99
    }
100
101
    /**
102
     * Get the placeholder tag for a column_name
103
     *
104
     * @param string $column_name
105
     * @return string
106
     */
107
    private function tagName(string $column_name): string
0 ignored issues
show
Unused Code introduced by
The method tagName() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
108
    {
109
        return array_flip(self::COLUMN_MAPPING)[$column_name] ?? '';
110
    }
111
112
    /**
113
     * Sanitize string for use in a SQL query.
114
     *
115
     * @param string $string
116
     * @return string
117
     */
118
    private function sanitizeString(string $string): string
119
    {
120
        return DB::connection()->getPdo()->quote($string);
121
    }
122
}
123