Gis   A
last analyzed

Complexity

Total Complexity 28

Size/Duplication

Total Lines 200
Duplicated Lines 0 %

Test Coverage

Coverage 67.62%

Importance

Changes 0
Metric Value
eloc 100
dl 0
loc 200
rs 10
c 0
b 0
f 0
ccs 71
cts 105
cp 0.6762
wmc 28

4 Methods

Rating   Name   Duplication   Size   Complexity  
A getDataTypes() 0 17 2
A createData() 0 14 4
D getFunctions() 0 87 15
B convertToWellKnownText() 0 37 7
1
<?php
2
3
declare(strict_types=1);
4
5
namespace PhpMyAdmin\Utils;
6
7
use PhpMyAdmin\DatabaseInterface;
8
9
use function array_map;
10
use function bin2hex;
11
use function mb_strtolower;
12
use function mb_strtoupper;
13
use function preg_match;
14
use function trim;
15
16
final class Gis
17
{
18
    /**
19
     * Converts GIS data to Well Known Text format
20
     *
21
     * @param string $data        GIS data
22
     * @param bool   $includeSRID Add SRID to the WKT
23
     *
24
     * @return string GIS data in Well Know Text format
25
     */
26 32
    public static function convertToWellKnownText(string $data, bool $includeSRID = false): string
27
    {
28
        // Convert to WKT format
29 32
        $hex = bin2hex($data);
30 32
        $spatialAsText = 'ASTEXT';
31 32
        $spatialSrid = 'SRID';
32 32
        $axisOrder = '';
33 32
        $dbi = DatabaseInterface::getInstance();
0 ignored issues
show
Deprecated Code introduced by
The function PhpMyAdmin\DatabaseInterface::getInstance() has been deprecated: Use dependency injection instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

33
        $dbi = /** @scrutinizer ignore-deprecated */ DatabaseInterface::getInstance();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
34 32
        $mysqlVersionInt = $dbi->getVersion();
35 32
        if ($mysqlVersionInt >= 50600) {
36 24
            $spatialAsText = 'ST_ASTEXT';
37 24
            $spatialSrid = 'ST_SRID';
38
        }
39
40 32
        if ($mysqlVersionInt >= 80001 && ! $dbi->isMariaDB()) {
41 8
            $axisOrder = ', \'axis-order=long-lat\'';
42
        }
43
44 32
        $wktsql = 'SELECT ' . $spatialAsText . "(x'" . $hex . "'" . $axisOrder . ')';
45 32
        if ($includeSRID) {
46 16
            $wktsql .= ', ' . $spatialSrid . "(x'" . $hex . "')";
47
        }
48
49 32
        $wktresult = $dbi->tryQuery($wktsql);
50 32
        $wktarr = [];
51 32
        if ($wktresult) {
52 32
            $wktarr = $wktresult->fetchRow();
53
        }
54
55 32
        $wktval = $wktarr[0] ?? '';
56
57 32
        if ($includeSRID) {
58 16
            $srid = $wktarr[1] ?? null;
59 16
            $wktval = "'" . $wktval . "'," . $srid;
60
        }
61
62 32
        return $wktval;
63
    }
64
65
    /**
66
     * Return GIS data types
67
     *
68
     * @param bool $upperCase whether to return values in upper case
69
     *
70
     * @return string[] GIS data types
71
     */
72
    public static function getDataTypes(bool $upperCase = false): array
73
    {
74
        $gisDataTypes = [
75
            'geometry',
76
            'point',
77
            'linestring',
78
            'polygon',
79
            'multipoint',
80
            'multilinestring',
81
            'multipolygon',
82
            'geometrycollection',
83
        ];
84
        if ($upperCase) {
85
            return array_map(mb_strtoupper(...), $gisDataTypes);
0 ignored issues
show
Bug introduced by
The type mb_strtoupper was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
86
        }
87
88
        return $gisDataTypes;
89
    }
90
91
    /**
92
     * Generates GIS data based on the string passed.
93
     *
94
     * @param string $gisString    GIS string
95
     * @param int    $mysqlVersion The mysql version as int
96
     *
97
     * @return string GIS data enclosed in 'ST_GeomFromText' or 'GeomFromText' function
98
     */
99 8
    public static function createData(string $gisString, int $mysqlVersion): string
100
    {
101 8
        $geomFromText = $mysqlVersion >= 50600 ? 'ST_GeomFromText' : 'GeomFromText';
102 8
        $gisString = trim($gisString);
103 8
        $geomTypes = '(POINT|MULTIPOINT|LINESTRING|MULTILINESTRING|POLYGON|MULTIPOLYGON|GEOMETRYCOLLECTION)';
104 8
        if (preg_match("/^'" . $geomTypes . "\(.*\)',[0-9]*$/i", $gisString)) {
105 8
            return $geomFromText . '(' . $gisString . ')';
106
        }
107
108 8
        if (preg_match('/^' . $geomTypes . '\(.*\)$/i', $gisString)) {
109
            return $geomFromText . "('" . $gisString . "')";
110
        }
111
112 8
        return $gisString;
113
    }
114
115
    /**
116
     * Returns the names and details of the functions
117
     * that can be applied on geometry data types.
118
     *
119
     * @param string|null $geomType if provided the output is limited to the functions
120
     *                          that are applicable to the provided geometry type.
121
     * @param bool        $binary   if set to false functions that take two geometries
122
     *                              as arguments will not be included.
123
     * @param bool        $display  if set to true separators will be added to the
124
     *                              output array.
125
     *
126
     * @return array<int|string,array<string,int|string>> names and details of the functions that can be applied on
127
     *                                                    geometry data types.
128
     */
129 4
    public static function getFunctions(
130
        string|null $geomType = null,
131
        bool $binary = true,
132
        bool $display = false,
133
    ): array {
134 4
        $funcs = [];
135 4
        if ($display) {
136
            $funcs[] = ['display' => ' '];
137
        }
138
139
        // Unary functions common to all geometry types
140 4
        $funcs['Dimension'] = ['params' => 1, 'type' => 'int'];
141 4
        $funcs['Envelope'] = ['params' => 1, 'type' => 'Polygon'];
142 4
        $funcs['GeometryType'] = ['params' => 1, 'type' => 'text'];
143 4
        $funcs['SRID'] = ['params' => 1, 'type' => 'int'];
144 4
        $funcs['IsEmpty'] = ['params' => 1, 'type' => 'int'];
145 4
        $funcs['IsSimple'] = ['params' => 1, 'type' => 'int'];
146
147 4
        $geomType = mb_strtolower(trim((string) $geomType));
148 4
        if ($display && $geomType !== 'geometry' && $geomType !== 'multipoint') {
149
            $funcs[] = ['display' => '--------'];
150
        }
151
152 4
        $spatialPrefix = '';
153 4
        if (DatabaseInterface::getInstance()->getVersion() >= 50601) {
0 ignored issues
show
Deprecated Code introduced by
The function PhpMyAdmin\DatabaseInterface::getInstance() has been deprecated: Use dependency injection instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

153
        if (/** @scrutinizer ignore-deprecated */ DatabaseInterface::getInstance()->getVersion() >= 50601) {

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
154
            // If MySQL version is greater than or equal 5.6.1,
155
            // use the ST_ prefix.
156 4
            $spatialPrefix = 'ST_';
157
        }
158
159
        // Unary functions that are specific to each geometry type
160 4
        if ($geomType === 'point') {
161
            $funcs[$spatialPrefix . 'X'] = ['params' => 1, 'type' => 'float'];
162
            $funcs[$spatialPrefix . 'Y'] = ['params' => 1, 'type' => 'float'];
163 4
        } elseif ($geomType === 'linestring') {
164
            $funcs['EndPoint'] = ['params' => 1, 'type' => 'point'];
165
            $funcs['GLength'] = ['params' => 1, 'type' => 'float'];
166
            $funcs['NumPoints'] = ['params' => 1, 'type' => 'int'];
167
            $funcs['StartPoint'] = ['params' => 1, 'type' => 'point'];
168
            $funcs['IsRing'] = ['params' => 1, 'type' => 'int'];
169 4
        } elseif ($geomType === 'multilinestring') {
170
            $funcs['GLength'] = ['params' => 1, 'type' => 'float'];
171
            $funcs['IsClosed'] = ['params' => 1, 'type' => 'int'];
172 4
        } elseif ($geomType === 'polygon') {
173
            $funcs['Area'] = ['params' => 1, 'type' => 'float'];
174
            $funcs['ExteriorRing'] = ['params' => 1, 'type' => 'linestring'];
175
            $funcs['NumInteriorRings'] = ['params' => 1, 'type' => 'int'];
176 4
        } elseif ($geomType === 'multipolygon') {
177
            $funcs['Area'] = ['params' => 1, 'type' => 'float'];
178
            $funcs['Centroid'] = ['params' => 1, 'type' => 'point'];
179
            // Not yet implemented in MySQL
180
            //$funcs['PointOnSurface'] = array('params' => 1, 'type' => 'point');
181 4
        } elseif ($geomType === 'geometrycollection') {
182
            $funcs['NumGeometries'] = ['params' => 1, 'type' => 'int'];
183
        }
184
185
        // If we are asked for binary functions as well
186 4
        if ($binary) {
187
            // section separator
188 4
            if ($display) {
189
                $funcs[] = ['display' => '--------'];
190
            }
191
192 4
            $funcs[$spatialPrefix . 'Crosses'] = ['params' => 2, 'type' => 'int'];
193 4
            $funcs[$spatialPrefix . 'Contains'] = ['params' => 2, 'type' => 'int'];
194 4
            $funcs[$spatialPrefix . 'Disjoint'] = ['params' => 2, 'type' => 'int'];
195 4
            $funcs[$spatialPrefix . 'Equals'] = ['params' => 2, 'type' => 'int'];
196 4
            $funcs[$spatialPrefix . 'Intersects'] = ['params' => 2, 'type' => 'int'];
197 4
            $funcs[$spatialPrefix . 'Overlaps'] = ['params' => 2, 'type' => 'int'];
198 4
            $funcs[$spatialPrefix . 'Touches'] = ['params' => 2, 'type' => 'int'];
199 4
            $funcs[$spatialPrefix . 'Within'] = ['params' => 2, 'type' => 'int'];
200
201 4
            if ($display) {
202
                $funcs[] = ['display' => '--------'];
203
            }
204
205
            // Minimum bounding rectangle functions
206 4
            $funcs['MBRContains'] = ['params' => 2, 'type' => 'int'];
207 4
            $funcs['MBRDisjoint'] = ['params' => 2, 'type' => 'int'];
208 4
            $funcs['MBREquals'] = ['params' => 2, 'type' => 'int'];
209 4
            $funcs['MBRIntersects'] = ['params' => 2, 'type' => 'int'];
210 4
            $funcs['MBROverlaps'] = ['params' => 2, 'type' => 'int'];
211 4
            $funcs['MBRTouches'] = ['params' => 2, 'type' => 'int'];
212 4
            $funcs['MBRWithin'] = ['params' => 2, 'type' => 'int'];
213
        }
214
215 4
        return $funcs;
216
    }
217
}
218