Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion system/DataCaster/Cast/FloatCast.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

namespace CodeIgniter\DataCaster\Cast;

use CodeIgniter\DataCaster\Exceptions\CastException;

/**
* Class FloatCast
*
Expand All @@ -30,6 +32,24 @@ public static function get(
self::invalidTypeValueError($value);
}

return (float) $value;
$precision = isset($params[0]) ? (int) $params[0] : null;

if ($precision === null) {
return (float) $value;
}

$mode = PHP_ROUND_HALF_UP; // Default mode

if (isset($params[1])) {
$mode = match (strtolower($params[1])) {
'up' => PHP_ROUND_HALF_UP,
'down' => PHP_ROUND_HALF_DOWN,
'even' => PHP_ROUND_HALF_EVEN,
'odd' => PHP_ROUND_HALF_ODD,
default => throw CastException::forInvalidFloatRoundingMode($params[1]),
};
}

return round((float) $value, $precision, $mode);
}
}
22 changes: 21 additions & 1 deletion system/Entity/Cast/FloatCast.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,30 @@

namespace CodeIgniter\Entity\Cast;

use CodeIgniter\DataCaster\Exceptions\CastException;

class FloatCast extends BaseCast
{
public static function get($value, array $params = []): float
{
return (float) $value;
$precision = isset($params[0]) ? (int) $params[0] : null;

if ($precision === null) {
return (float) $value;
}

$mode = PHP_ROUND_HALF_UP; // Default mode

if (isset($params[1])) {
$mode = match (strtolower($params[1])) {
'up' => PHP_ROUND_HALF_UP,
'down' => PHP_ROUND_HALF_DOWN,
'even' => PHP_ROUND_HALF_EVEN,
'odd' => PHP_ROUND_HALF_ODD,
default => throw CastException::forInvalidFloatRoundingMode($params[1]),
};
}

return round((float) $value, $precision, $mode);
}
}
10 changes: 10 additions & 0 deletions system/Entity/Exceptions/CastException.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,4 +122,14 @@ public static function forInvalidEnumType(string $expectedClass, string $actualC
{
return new static(lang('Cast.enumInvalidType', [$actualClass, $expectedClass]));
}

/**
* Thrown when an invalid rounding mode is provided for float casting.
*
* @return static
*/
public static function forInvalidFloatRoundingMode(string $mode)
{
return new static(lang('Cast.floatInvalidRoundingMode', [$mode]));
}
}
29 changes: 15 additions & 14 deletions system/Language/en/Cast.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,19 @@

// Cast language settings
return [
'baseCastMissing' => 'The "{0}" class must inherit the "CodeIgniter\Entity\Cast\BaseCast" class.',
'enumInvalidCaseName' => 'Invalid case name "{0}" for enum "{1}".',
'enumInvalidType' => 'Expected enum of type "{1}", but received "{0}".',
'enumInvalidValue' => 'Invalid value "{1}" for enum "{0}".',
'enumMissingClass' => 'Enum class must be specified for enum casting.',
'enumNotEnum' => 'The "{0}" is not a valid enum class.',
'invalidCastMethod' => 'The "{0}" is invalid cast method, valid methods are: ["get", "set"].',
'invalidTimestamp' => 'Type casting "timestamp" expects a correct timestamp.',
'jsonErrorCtrlChar' => 'Unexpected control character found.',
'jsonErrorDepth' => 'Maximum stack depth exceeded.',
'jsonErrorStateMismatch' => 'Underflow or the modes mismatch.',
'jsonErrorSyntax' => 'Syntax error, malformed JSON.',
'jsonErrorUnknown' => 'Unknown error.',
'jsonErrorUtf8' => 'Malformed UTF-8 characters, possibly incorrectly encoded.',
'baseCastMissing' => 'The "{0}" class must inherit the "CodeIgniter\Entity\Cast\BaseCast" class.',
'enumInvalidCaseName' => 'Invalid case name "{0}" for enum "{1}".',
'enumInvalidType' => 'Expected enum of type "{1}", but received "{0}".',
'enumInvalidValue' => 'Invalid value "{1}" for enum "{0}".',
'enumMissingClass' => 'Enum class must be specified for enum casting.',
'enumNotEnum' => 'The "{0}" is not a valid enum class.',
'invalidCastMethod' => 'The "{0}" is invalid cast method, valid methods are: ["get", "set"].',
'invalidTimestamp' => 'Type casting "timestamp" expects a correct timestamp.',
'jsonErrorCtrlChar' => 'Unexpected control character found.',
'jsonErrorDepth' => 'Maximum stack depth exceeded.',
'jsonErrorStateMismatch' => 'Underflow or the modes mismatch.',
'jsonErrorSyntax' => 'Syntax error, malformed JSON.',
'jsonErrorUnknown' => 'Unknown error.',
'jsonErrorUtf8' => 'Malformed UTF-8 characters, possibly incorrectly encoded.',
'floatInvalidRoundingMode' => 'Invalid rounding mode "{0}" for float casting.',
];
56 changes: 56 additions & 0 deletions tests/system/DataConverter/DataConverterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,62 @@ public static function provideConvertDataFromDB(): iterable
'temp' => 15.9,
],
],
'float precise' => [
[
'id' => 'int',
'temp' => 'float[2]',
],
[
'id' => '1',
'temp' => '15.98765',
],
[
'id' => 1,
'temp' => 15.99,
],
],
'float precise-down' => [
[
'id' => 'int',
'temp' => 'float[2,down]',
],
[
'id' => '1',
'temp' => '1.235',
],
[
'id' => 1,
'temp' => 1.23,
],
],
'float precise-even' => [
[
'id' => 'int',
'temp' => 'float[2,even]',
],
[
'id' => '1',
'temp' => '20.005',
],
[
'id' => 1,
'temp' => 20.00,
],
],
'float precise-odd' => [
[
'id' => 'int',
'temp' => 'float[2,odd]',
],
[
'id' => '1',
'temp' => '1.255',
],
[
'id' => 1,
'temp' => 1.25,
],
],
'enum string-backed' => [
[
'id' => 'int',
Expand Down
5 changes: 5 additions & 0 deletions user_guide_src/source/changelogs/v4.8.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,11 @@ Validation

- Custom rule methods that set an error via the ``&$error`` reference parameter now support the ``{field}``, ``{param}``, and ``{value}`` placeholders, consistent with language-file and ``setRule()``/``setRules()`` error messages.

Entities
========

- **Float and Double Casting:** Added support for precision and rounding mode when casting to float or double in entities.

Others
======

Expand Down
1 change: 1 addition & 0 deletions user_guide_src/source/models/entities.rst
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ Add a question mark at the beginning of type to mark property as nullable, i.e.,

.. note:: **int-bool** can be used since v4.3.0.
.. note:: **enum** can be used since v4.7.0.
.. note:: Since v4.8.0, you can also pass parameters to **float** and **double** types to specify the number of decimal places and rounding mode, i.e., **float[2,even]**.

For example, if you had a User entity with an ``is_banned`` property, you can cast it as a boolean:

Expand Down
Loading