Passed
Push — main ( ad76dd...bc3fc8 )
by Jonathan
12:59
created

PlacesReferenceTableService::tagName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
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) 2021-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\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
     * Sanitize string for use in a SQL query.
103
     *
104
     * @param string $string
105
     * @return string
106
     */
107
    private function sanitizeString(string $string): string
108
    {
109
        return DB::connection()->getPdo()->quote($string);
110
    }
111
}
112