Browse Source

Make FloatType locale aware

Format numeric strings input as float point
CauanCabral 11 years ago
parent
commit
4ecc8528e1
2 changed files with 96 additions and 0 deletions
  1. 55 0
      src/Database/Type/FloatType.php
  2. 41 0
      tests/TestCase/Database/Type/FloatTypeTest.php

+ 55 - 0
src/Database/Type/FloatType.php

@@ -26,6 +26,21 @@ class FloatType extends \Cake\Database\Type
 {
 {
 
 
     /**
     /**
+     * The class to use for representing number objects
+     *
+     * @var string
+     */
+    public static $numberClass = 'Cake\I18n\Number';
+
+    /**
+     * Whether numbers should be parsed using a locale aware parser
+     * when marshalling string inputs.
+     *
+     * @var bool
+     */
+    protected $_useLocaleParser = false;
+
+    /**
      * Convert integer data into the database format.
      * Convert integer data into the database format.
      *
      *
      * @param string|resource $value The value to convert.
      * @param string|resource $value The value to convert.
@@ -81,7 +96,47 @@ class FloatType extends \Cake\Database\Type
         }
         }
         if (is_numeric($value)) {
         if (is_numeric($value)) {
             return (float)$value;
             return (float)$value;
+        } elseif (is_string($value) && $this->_useLocaleParser) {
+           return $this->_parseValue($value);
         }
         }
+
         return $value;
         return $value;
     }
     }
+
+    /**
+     * Sets whether or not to parse numbers passed to the marshal() function
+     * by using a locale aware parser.
+     *
+     * @param bool $enable Whether or not to enable
+     * @return $this
+     */
+    public function useLocaleParser($enable = true)
+    {
+        if ($enable === false) {
+            $this->_useLocaleParser = $enable;
+            return $this;
+        }
+        if (static::$numberClass === 'Cake\I18n\Number' ||
+            is_subclass_of(static::$numberClass, 'Cake\I18n\Number')
+        ) {
+            $this->_useLocaleParser = $enable;
+            return $this;
+        }
+        throw new RuntimeException(
+            sprintf('Cannot use locale parsing with the %s class', static::$numberClass)
+        );
+    }
+
+    /**
+     * Converts a string into a float point after parseing it using the locale
+     * aware parser.
+     *
+     * @param string $value The value to parse and convert to an float.
+     * @return float
+     */
+    protected function _parseValue($value)
+    {
+        $class = static::$numberClass;
+        return $class::parseFloat($value);
+    }
 }
 }

+ 41 - 0
tests/TestCase/Database/Type/FloatTypeTest.php

@@ -14,6 +14,7 @@
  */
  */
 namespace Cake\Test\TestCase\Database\Type;
 namespace Cake\Test\TestCase\Database\Type;
 
 
+use Cake\I18n\I18n;
 use Cake\Database\Type;
 use Cake\Database\Type;
 use Cake\Database\Type\FloatType;
 use Cake\Database\Type\FloatType;
 use Cake\TestSuite\TestCase;
 use Cake\TestSuite\TestCase;
@@ -35,6 +36,20 @@ class FloatTypeTest extends TestCase
         parent::setUp();
         parent::setUp();
         $this->type = Type::build('float');
         $this->type = Type::build('float');
         $this->driver = $this->getMock('Cake\Database\Driver');
         $this->driver = $this->getMock('Cake\Database\Driver');
+        $this->locale = I18n::locale();
+
+        I18n::locale($this->locale);
+    }
+
+    /**
+     * tearDown method
+     *
+     * @return void
+     */
+    public function tearDown()
+    {
+        parent::tearDown();
+        I18n::locale($this->locale);
     }
     }
 
 
     /**
     /**
@@ -94,6 +109,32 @@ class FloatTypeTest extends TestCase
     }
     }
 
 
     /**
     /**
+     * Tests marshalling numbers using the locale aware parser
+     *
+     * @return void
+     */
+    public function testMarshalWithLocaleParsing()
+    {
+        I18n::locale('de_DE');
+        $this->type->useLocaleParser();
+        $expected = 1234.53;
+        $result = $this->type->marshal('1.234,53');
+        $this->assertEquals($expected, $result);
+
+        I18n::locale('en_US');
+        $this->type->useLocaleParser();
+        $expected = 1234;
+        $result = $this->type->marshal('1,234');
+        $this->assertEquals($expected, $result);
+
+        I18n::locale('pt_BR');
+        $this->type->useLocaleParser();
+        $expected = 5987123.231;
+        $result = $this->type->marshal('5.987.123,231');
+        $this->assertEquals($expected, $result);
+    }
+
+    /**
      * Test that the PDO binding type is correct.
      * Test that the PDO binding type is correct.
      *
      *
      * @return void
      * @return void