Skip to content
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).

## Unreleased

### Fixed

- Fix an issue where data are not formatted when coming from a field plugin's custom field.

## [2.15.10] - 2026-08-07

### Fixed
Expand Down
17 changes: 16 additions & 1 deletion inc/commoninjectionlib.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -1098,6 +1098,14 @@ private function reformatThirdPass()
//Get search option associated with the field
$option = self::findSearchOption($searchOptions, $field);

if ($option && !isset($option['checktype'])) {
// In some cases, float datatype is wrongly detected as string, decimal or number, so we check that first.
//Regex matches all decimal formats accepted by glpi
$option['checktype'] = (preg_match($this->getFloatDetectionRegex(), $value) !== 0)
? "float"
: $option['datatype'];
}

// Check some types
switch ($option['checktype'] ?? 'text') {
case "date":
Expand Down Expand Up @@ -1299,6 +1307,13 @@ private static function reformatMacAddress($mac)
return $mac;
}

//--------------------------------------------------//
//----------- Utility methods -----------------------//
//------------------------------------------------//
public function getFloatDetectionRegex(): string
{
return '/^(?:(?:\d{1,3}(?: \d{3})+|\d+)[.,]|\d{1,3}(?:,\d{3})+\.)\d+$/';
}

//--------------------------------------------------//
//----------- Check methods -----------------------//
Expand Down Expand Up @@ -1397,7 +1412,7 @@ private function checkType($injectionClass, $option, $field_name, $data, $mandat
{

if (!empty($option)) {
$field_type = ($option['checktype'] ?? 'text');
$field_type = ($option['checktype'] ?? $option['datatype'] ?? 'text');

//If no data provided AND this mapping is not mandatory
if (
Expand Down
100 changes: 100 additions & 0 deletions tests/unit/CommonInjectionLibFloatDetectionTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<?php

/**
* -------------------------------------------------------------------------
* DataInjection plugin for GLPI
* -------------------------------------------------------------------------
*
* LICENSE
*
* This file is part of DataInjection.
*
* DataInjection is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* DataInjection is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with DataInjection. If not, see <http://www.gnu.org/licenses/>.
* -------------------------------------------------------------------------
* @copyright Copyright (C) 2007-2023 by DataInjection plugin team.
* @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html
* @link https://github.com/pluginsGLPI/datainjection
* -------------------------------------------------------------------------
*/

namespace GlpiPlugin\Datainjection\Tests\Unit;

use Glpi\Tests\DbTestCase;
use PluginDatainjectionCommonInjectionLib;
use PluginDatainjectionComputerInjection;

require_once dirname(__DIR__, 2) . '/inc/injectioninterface.class.php';
require_once dirname(__DIR__, 2) . '/inc/commoninjectionlib.class.php';
require_once dirname(__DIR__, 2) . '/inc/computerinjection.class.php';

/**
* Covers the float-detection regex used by reformatThirdPass() to derive
* $option['checktype'] when a search option (e.g. a custom field coming from
* a third-party plugin) only has a 'datatype' and no explicit 'checktype'.
*
* The regex under test is not hardcoded here: it is retrieved from
* PluginDatainjectionCommonInjectionLib::getFloatDetectionRegex(), the same
* shared source reformatThirdPass() itself calls, so this test can never
* drift out of sync with the actual pattern shipped in the code.
*/
final class CommonInjectionLibFloatDetectionTest extends DbTestCase
{
private static function getFloatDetectionRegex(): string
{
$lib = new PluginDatainjectionCommonInjectionLib(new PluginDatainjectionComputerInjection());

return $lib->getFloatDetectionRegex();
}

public static function floatDetectionProvider(): array
{
return [
// Accepted formats
'plain dot decimal' => ['1234.56', true],
'plain comma decimal' => ['1234,56', true],
'leading zero decimal' => ['0.5', true],
'space-grouped thousands, dot decimal' => ['1 234.56', true],
'space-grouped thousands, comma decimal' => ['1 234,56', true],
'multiple space groups, comma decimal' => ['12 345 678,90', true],
'comma-grouped thousands, dot decimal' => ['1,234.56', true],
'multiple comma groups, dot decimal' => ['12,345,678.90', true],
'basic comma decimal, no grouping' => ['12,34', true],

// Rejected formats (should fall back to $option['datatype'])
'plain integer, no separator' => ['1234', false],
'empty string' => ['', false],
'non numeric text' => ['abc', false],
'multiple dots (malformed)' => ['1234.56.78', false],
'comma-grouped integer, no decimal part' => ['1,234,567', false],
'space-grouped integer, no decimal part' => ['1 234', false],
'leading dot, no integer part' => ['.56', false],
'negative float (unsupported by regex)' => ['-1234.56', false],
Comment thread
jdurand-teclib marked this conversation as resolved.
'malformed space grouping (2nd group not 3 digits)' => ['12 34.56', false],
'malformed comma grouping (1st group over 3 digits)' => ['1234,567.89', false],
'leading whitespace' => [' 1234.56', false],
'trailing whitespace' => ['1234.56 ', false],
'scientific notation (unsupported by regex)' => ['1.5e10', false],
];
}

/**
* @dataProvider floatDetectionProvider
*/
public function testFloatDetectionRegex(string $value, bool $expected_match): void
{
$regex = self::getFloatDetectionRegex();

self::assertSame($expected_match, preg_match($regex, $value) !== 0);
}
}