Skip to content

Commit 4cd3474

Browse files
Daniel BerthereauDaniel Berthereau
authored andcommitted
Added a way to manage bad format in batch edit.
1 parent 94f1220 commit 4cd3474

4 files changed

Lines changed: 98 additions & 26 deletions

File tree

Module.php

Lines changed: 69 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -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*$
652671
REGEX_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*$
665679
REGEX_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
669711
WHERE
670712
`value`.`resource_id` IN (:resource_ids)
@@ -690,10 +732,12 @@ protected function convertLiteralToCoordinates(array $ids, array $data): void
690732
SQL;
691733
$connection->executeStatement($sql, $bind, $types);
692734

735+
// Normalize existing values when needed.
693736
$sql = <<<SQL
694737
UPDATE `value`
695738
SET
696-
`value`.`type` = "geography:coordinates"
739+
`value`.`type` = "geography:coordinates",
740+
`value`.`value` = CONCAT($y, ",", $x)
697741
$whereSql
698742
SQL;
699743
$connection->executeStatement($sql, $bind, $types);

asset/js/data-type-geometry.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@
204204

205205
// Batch edit form.
206206

207-
$('#geometry_manage_coordinates_features, #geometry_convert_literal_to_coordinates, #geometry_convert_literal_order, #geometry_from_property, #geometry_to_property').closest('.field')
207+
$('#geometry_manage_coordinates_features, #geometry_convert_literal_to_coordinates, #geometry_convert_literal_order, #geometry_convert_literal_strict, #geometry_from_property, #geometry_to_property').closest('.field')
208208
.wrapAll('<fieldset id="geometry" class="field-container">');
209209
$('#geometry')
210210
.prepend('<legend>' + Omeka.jsTranslate('Geographic coordinates') + '</legend>');

src/Form/BatchEditFieldset.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,19 @@ public function init(): void
5252
'data-collection-action' => 'replace',
5353
],
5454
])
55+
->add([
56+
'name' => 'convert_literal_strict',
57+
'type' => Element\Checkbox::class,
58+
'options' => [
59+
'label' => 'Check format strictly ("," as separator)', // @translate
60+
],
61+
'attributes' => [
62+
'id' => 'geometry_convert_literal_strict',
63+
'value' => 'latitude_longitude',
64+
// This attribute is required to make "batch edit all" working.
65+
'data-collection-action' => 'replace',
66+
],
67+
])
5568
->add([
5669
'name' => 'manage_coordinates_features',
5770
'type' => Element\Select::class,

src/View/Helper/DatabaseVersion.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,21 @@ public function supportGeographicSearch(): bool
7171
}
7272
}
7373

74+
/**
75+
* Check if Omeka database has minimum requirements to use `regexp_substr`.
76+
*/
77+
public function supportRegexpExt(): bool
78+
{
79+
switch ($this->db['db']) {
80+
case 'mysql':
81+
return version_compare($this->db['version'], '8.0', '>=');
82+
case 'mariadb':
83+
return version_compare($this->db['version'], '10.0.5', '>=');
84+
default:
85+
return false;
86+
}
87+
}
88+
7489
/**
7590
* Check if the Omeka database requires myIsam to support Geometry.
7691
*

0 commit comments

Comments
 (0)