GisDataEditorController.php 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. <?php
  2. /**
  3. * Editor for Geometry data types.
  4. */
  5. declare(strict_types=1);
  6. namespace PhpMyAdmin\Controllers;
  7. use PhpMyAdmin\Gis\GisFactory;
  8. use PhpMyAdmin\Gis\GisVisualization;
  9. use PhpMyAdmin\Http\ServerRequest;
  10. use function array_merge;
  11. use function in_array;
  12. use function intval;
  13. use function is_array;
  14. use function mb_strtoupper;
  15. use function preg_match;
  16. use function trim;
  17. /**
  18. * Editor for Geometry data types.
  19. */
  20. class GisDataEditorController extends AbstractController
  21. {
  22. private const GIS_TYPES = [
  23. 'POINT',
  24. 'MULTIPOINT',
  25. 'LINESTRING',
  26. 'MULTILINESTRING',
  27. 'POLYGON',
  28. 'MULTIPOLYGON',
  29. 'GEOMETRYCOLLECTION',
  30. ];
  31. public function __invoke(ServerRequest $request): void
  32. {
  33. global $gis_data, $geom_type, $gis_obj, $srid, $wkt, $wkt_with_zero;
  34. global $result, $visualizationSettings, $data, $visualization, $open_layers, $geom_count, $dbi;
  35. /** @var string|null $field */
  36. $field = $request->getParsedBodyParam('field');
  37. /** @var array|null $gisDataParam */
  38. $gisDataParam = $request->getParsedBodyParam('gis_data');
  39. /** @var string $type */
  40. $type = $request->getParsedBodyParam('type', 'GEOMETRY');
  41. /** @var string|null $value */
  42. $value = $request->getParsedBodyParam('value');
  43. /** @var string|null $generate */
  44. $generate = $request->getParsedBodyParam('generate');
  45. /** @var string|null $inputName */
  46. $inputName = $request->getParsedBodyParam('input_name');
  47. if (! isset($field)) {
  48. return;
  49. }
  50. // Get data if any posted
  51. $gis_data = [];
  52. if (is_array($gisDataParam)) {
  53. $gis_data = $gisDataParam;
  54. }
  55. $gis_data = $this->validateGisData($gis_data, $type, $value);
  56. $geom_type = $gis_data['gis_type'];
  57. // Generate parameters from value passed.
  58. $gis_obj = GisFactory::factory($geom_type);
  59. if ($gis_obj === false) {
  60. return;
  61. }
  62. if (isset($value)) {
  63. $gis_data = array_merge(
  64. $gis_data,
  65. $gis_obj->generateParams($value)
  66. );
  67. }
  68. // Generate Well Known Text
  69. $srid = isset($gis_data['srid']) && $gis_data['srid'] != '' ? (int) $gis_data['srid'] : 0;
  70. $wkt = $gis_obj->generateWkt($gis_data, 0);
  71. $wkt_with_zero = $gis_obj->generateWkt($gis_data, 0, '0');
  72. $result = "'" . $wkt . "'," . $srid;
  73. // Generate SVG based visualization
  74. $visualizationSettings = [
  75. 'width' => 450,
  76. 'height' => 300,
  77. 'spatialColumn' => 'wkt',
  78. 'mysqlVersion' => $dbi->getVersion(),
  79. 'isMariaDB' => $dbi->isMariaDB(),
  80. ];
  81. $data = [
  82. [
  83. 'wkt' => $wkt_with_zero,
  84. 'srid' => $srid,
  85. ],
  86. ];
  87. $visualization = GisVisualization::getByData($data, $visualizationSettings)
  88. ->toImage('svg');
  89. $open_layers = GisVisualization::getByData($data, $visualizationSettings)
  90. ->asOl();
  91. // If the call is to update the WKT and visualization make an AJAX response
  92. if ($generate) {
  93. $this->response->addJSON([
  94. 'result' => $result,
  95. 'visualization' => $visualization,
  96. 'openLayers' => $open_layers,
  97. ]);
  98. return;
  99. }
  100. $geom_count = 1;
  101. if ($geom_type === 'GEOMETRYCOLLECTION') {
  102. $geom_count = isset($gis_data[$geom_type]['geom_count'])
  103. ? intval($gis_data[$geom_type]['geom_count']) : 1;
  104. if (isset($gis_data[$geom_type]['add_geom'])) {
  105. $geom_count++;
  106. }
  107. }
  108. $templateOutput = $this->template->render('gis_data_editor_form', [
  109. 'width' => $visualizationSettings['width'],
  110. 'height' => $visualizationSettings['height'],
  111. 'field' => $field,
  112. 'input_name' => $inputName,
  113. 'srid' => $srid,
  114. 'visualization' => $visualization,
  115. 'open_layers' => $open_layers,
  116. 'column_type' => mb_strtoupper($type),
  117. 'gis_types' => self::GIS_TYPES,
  118. 'geom_type' => $geom_type,
  119. 'geom_count' => $geom_count,
  120. 'gis_data' => $gis_data,
  121. 'result' => $result,
  122. ]);
  123. $this->response->addJSON(['gis_editor' => $templateOutput]);
  124. }
  125. /**
  126. * Extract type from the initial call and make sure that it's a valid one.
  127. * Extract from field's values if available, if not use the column type passed.
  128. *
  129. * @param mixed[] $gis_data
  130. *
  131. * @return mixed[]
  132. * @psalm-return array{gis_type:value-of<self::GIS_TYPES>}&mixed[]
  133. */
  134. private function validateGisData(array $gis_data, string $type, ?string $value): array
  135. {
  136. if (! isset($gis_data['gis_type']) || ! in_array($gis_data['gis_type'], self::GIS_TYPES, true)) {
  137. if ($type !== '') {
  138. $gis_data['gis_type'] = mb_strtoupper($type);
  139. }
  140. if (isset($value) && trim($value) !== '' && preg_match('/^\'?(\w+)\b/', $value, $matches)) {
  141. $gis_data['gis_type'] = $matches[1];
  142. }
  143. if (! isset($gis_data['gis_type']) || (! in_array($gis_data['gis_type'], self::GIS_TYPES, true))) {
  144. $gis_data['gis_type'] = self::GIS_TYPES[0];
  145. }
  146. }
  147. return $gis_data;
  148. }
  149. }