@@ -464,6 +464,27 @@ public function handleResourceBatchUpdatePreprocess(Event $event): void
464464 return ;
465465 }
466466
467+ $ services = $ this ->getServiceLocator ();
468+
469+ if (!empty ($ post ['geometry ' ]['convert_literal_to_coordinates ' ])
470+ && empty ($ post ['geometry ' ]['convert_literal_strict ' ])
471+ /** @see \DataTypeGeometry\View\Helper\DatabaseVersion::supportRegexpExt() */
472+ && !$ services ->get ('ViewHelperManager ' )->get ('databaseVersion ' )->supportRegexpExt ()
473+ ) {
474+ /**
475+ * @var \Laminas\Log\Logger $logger
476+ * @var \Omeka\Mvc\Controller\Plugin\Messenger $messenger
477+ */
478+ $ logger = $ services ->get ('Omeka\Logger ' );
479+ $ messenger = $ services ->get ('ControllerPluginManager ' )->get ('messenger ' );
480+ $ message = new Message ('Your database does not support the function `regexp_substr`. Upgrade it to MariaDB 10.0.5 or MySQL 8.0. ' ); // @translate
481+ $ logger ->err ($ message );
482+ $ messenger ->addError ($ message );
483+ unset($ data ['geometry ' ]);
484+ $ event ->setParam ('data ' , $ data );
485+ return ;
486+ }
487+
467488 $ manage = $ post ['geometry ' ]['manage_coordinates_features ' ] ?? null ;
468489 if (!in_array ($ manage , ['sync ' , 'coordinates_to_features ' , 'features_to_coordinates ' ])) {
469490 unset($ data ['geometry ' ]);
@@ -472,7 +493,7 @@ public function handleResourceBatchUpdatePreprocess(Event $event): void
472493 }
473494
474495 /** @var \Common\Stdlib\EasyMeta $easyMeta */
475- $ easyMeta = $ this -> getServiceLocator () ->get ('EasyMeta ' );
496+ $ easyMeta = $ services ->get ('EasyMeta ' );
476497
477498 if (empty ($ post ['geometry ' ]['from_properties ' ])
478499 || in_array ('all ' , $ post ['geometry ' ]['from_properties ' ])
@@ -507,7 +528,8 @@ public function handleResourceBatchUpdatePreprocess(Event $event): void
507528 $ data ['geometry ' ] = $ post ['geometry ' ];
508529 $ data ['geometry ' ]['convert_literal_to_coordinates ' ] = !empty ($ data ['geometry ' ]['convert_literal_to_coordinates ' ]);
509530 $ data ['geometry ' ]['convert_literal_order ' ] = $ data ['geometry ' ]['convert_literal_order ' ] ?? null ;
510- $ data ['geometry ' ]['srid ' ] = $ this ->getServiceLocator ()->get ('Omeka\Settings ' )
531+ $ data ['geometry ' ]['convert_literal_strict ' ] = !empty ($ data ['geometry ' ]['convert_literal_strict ' ]);
532+ $ data ['geometry ' ]['srid ' ] = $ services ->get ('Omeka\Settings ' )
511533 ->get ('datatypegeometry_locate_srid ' , Geography::DEFAULT_SRID );
512534
513535 $ event ->setParam ('data ' , $ data );
@@ -516,21 +538,24 @@ public function handleResourceBatchUpdatePreprocess(Event $event): void
516538 /**
517539 * Process action on batch update (all or partial) via direct sql.
518540 *
519- * Data may need to be reindexed if a module like Search is used, even if
520- * the results are probably the same with a simple trimming.
541+ * Data should be reindexed.
521542 *
522543 * @param Event $event
523544 */
524545 public function handleResourceBatchUpdatePost (Event $ event ): void
525546 {
547+ // TODO Event data is not available here, so use request content.
548+ // $data = $event->getParam('data');
526549 /** @var \Omeka\Api\Request $request */
527550 $ request = $ event ->getParam ('request ' );
528551 $ data = $ request ->getContent ();
552+
529553 if (empty ($ data ['geometry ' ])
530554 || !array_filter ($ data ['geometry ' ])
531555 || (empty ($ data ['geometry ' ]['convert_literal_to_coordinates ' ])
532556 && empty ($ data ['geometry ' ]['manage_coordinates_features ' ])
533557 )
558+ || empty ($ data ['geometry ' ]['from_properties ' ])
534559 ) {
535560 return ;
536561 }
@@ -546,6 +571,7 @@ public function handleResourceBatchUpdatePost(Event $event): void
546571 $ easyMeta = $ this ->getServiceLocator ()->get ('EasyMeta ' );
547572 $ data ['geometry ' ]['convert_literal_to_coordinates ' ] = !empty ($ data ['geometry ' ]['convert_literal_to_coordinates ' ]);
548573 $ data ['geometry ' ]['convert_literal_order ' ] = $ data ['geometry ' ]['convert_literal_order ' ] ?? null ;
574+ $ data ['geometry ' ]['convert_literal_strict ' ] = !empty ($ data ['geometry ' ]['convert_literal_strict ' ]);
549575 $ data ['geometry ' ]['from_properties_ids ' ] = empty ($ data ['geometry ' ]['from_properties ' ]) || in_array ('all ' , $ data ['geometry ' ]['from_properties ' ])
550576 ? []
551577 : $ easyMeta ->propertyIds ($ data ['geometry ' ]['from_properties ' ]);
@@ -636,35 +662,51 @@ protected function convertLiteralToCoordinates(array $ids, array $data): void
636662 // TODO Don't use (?:xxx|yyy) for compatibility with mysql 5.6.
637663 // The single quote simplifies escaping of regex. Use nowdoc to avoid
638664 // issues with backslashes.
665+ // Regex sql requires double backslashs, so check variables and nowdocs.
639666 $ isLongLat = $ data ['geometry ' ]['convert_literal_order ' ] === 'longitude_latitude ' ;
640- if ($ isLongLat ) {
641- $ selectSql = <<<'SQL'
642- CONCAT(
643- "POINT(",
644- TRIM(SUBSTRING_INDEX(TRIM(`value`.`value`), ",", 1)),
645- " ",
646- TRIM(SUBSTRING_INDEX(TRIM(`value`.`value`), ",", -1)),
647- ")"
648- )
649- SQL;
667+ $ isStrictLiteral = !empty ($ data ['geometry ' ]['convert_literal_strict ' ]);
668+ if ($ isLongLat && $ isStrictLiteral ) {
650669 $ regexSql = <<<'REGEX_SQL'
651670^\\s*(?<longitude>[+-]?(?:180(?:\\.0+)?|(?:(?:1[0-7]\\d)|(?:[1-9]?\\d))(?:\\.\\d+)?))\\s*,\\s*(?<latitude>[+-]?(?:[1-8]?\\d(?:\\.\\d+)?|90(?:\\.0+)?))\\s*$
652671REGEX_SQL;
653- } else {
654- $ selectSql = <<<'SQL'
655- CONCAT(
656- "POINT(",
657- TRIM(SUBSTRING_INDEX(TRIM(`value`.`value`), ",", -1)),
658- " ",
659- TRIM(SUBSTRING_INDEX(TRIM(`value`.`value`), ",", 1)),
660- ")"
661- )
662- SQL;
672+ } elseif ($ isLongLat && !$ isStrictLiteral ) {
673+ $ regexSql = <<<'REGEX_SQL'
674+ ^\\s*(?<longitude>[+-]?(?:180(?:\\.0+)?|(?:(?:1[0-7]\\d)|(?:[1-9]?\\d))(?:\\.\\d+)?))[^\\d.+-]+(?<latitude>[+-]?(?:[1-8]?\\d(?:\\.\\d+)?|90(?:\\.0+)?))\\s*$
675+ REGEX_SQL;
676+ } elseif ($ isStrictLiteral ) {
663677 $ regexSql = <<<'REGEX_SQL'
664678^\\s*(?<latitude>[+-]?(?:[1-8]?\\d(?:\\.\\d+)?|90(?:\\.0+)?))\\s*,\\s*(?<longitude>[+-]?(?:180(?:\\.0+)?|(?:(?:1[0-7]\\d)|(?:[1-9]?\\d))(?:\\.\\d+)?))\\s*$
665679REGEX_SQL;
680+ } else {
681+ $ regexSql = <<<'REGEX_SQL'
682+ ^\\s*(?<latitude>[+-]?(?:[1-8]?\\d(?:\\.\\d+)?|90(?:\\.0+)?))[^\\d.+-]+(?<longitude>[+-]?(?:180(?:\\.0+)?|(?:(?:1[0-7]\\d)|(?:[1-9]?\\d))(?:\\.\\d+)?))\\s*$
683+ REGEX_SQL;
684+ }
685+
686+ if ($ isStrictLiteral ) {
687+ // Process is quicker than regex here.
688+ $ first = 'TRIM(SUBSTRING_INDEX(TRIM(`value`.`value`), ",", 1)) ' ;
689+ $ second = 'TRIM(SUBSTRING_INDEX(TRIM(`value`.`value`), ",", -1)) ' ;
690+ } else {
691+ // The whole value is already checked, so a basic pattern is enough.
692+ // "[0-9]" instead of "\d" avoids a quadruple backslashes variable.
693+ $ first = "REGEXP_SUBSTR(`value`.`value`, '[0-9.+-]+') " ;
694+ $ second = "REGEXP_SUBSTR(REGEXP_SUBSTR(`value`.`value`, '[^0-9.+-]+[0-9.+-]+'), '[0-9.+-]+') " ;
666695 }
667696
697+ if ($ isLongLat ) {
698+ $ x = $ first ;
699+ $ y = $ second ;
700+ } else {
701+ $ x = $ second ;
702+ $ y = $ first ;
703+ }
704+
705+ $ selectSql = <<<SQL
706+ CONCAT("POINT(", $ x, " ", $ y, ")")
707+ SQL ;
708+
709+ // Process only literal strings to avoid to reprocess geometric data.
668710 $ whereSql = <<<SQL
669711WHERE
670712 `value`.`resource_id` IN (:resource_ids)
@@ -690,10 +732,12 @@ protected function convertLiteralToCoordinates(array $ids, array $data): void
690732SQL ;
691733 $ connection ->executeStatement ($ sql , $ bind , $ types );
692734
735+ // Normalize existing values when needed.
693736 $ sql = <<<SQL
694737UPDATE `value`
695738SET
696- `value`.`type` = "geography:coordinates"
739+ `value`.`type` = "geography:coordinates",
740+ `value`.`value` = CONCAT( $ y, ",", $ x)
697741$ whereSql
698742SQL ;
699743 $ connection ->executeStatement ($ sql , $ bind , $ types );
0 commit comments