Skip to content

Commit 069abe5

Browse files
committed
Implement casting to Decimal in DecimalObjectCast trait
1 parent fbc4137 commit 069abe5

File tree

1 file changed

+90
-12
lines changed

1 file changed

+90
-12
lines changed

Diff for: src/DecimalObjectCast.php

+90-12
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,104 @@
88
* "decimal" cast uses `number_format`, but we can utilize the `toFixed` method
99
* provided by Decimal\Decimal to prepare the value.
1010
*
11-
* This trait does not provide a cast from string to Decimal; this should be
12-
* done manually using an accessor like `getPriceAttribute`, which should return
13-
* a new Decimal\Decimal using the precision of the column in the database.
11+
* This trait extends the default behavior by allowing the precision and scale
12+
* of the decimal value to be specified via the attribute's casting definition.
13+
* For example, `decimal:2:8` would cast the attribute to a Decimal with 2 digits
14+
* of scale and 8 digits of precision.
1415
*/
1516
trait DecimalObjectCast
1617
{
1718
/**
18-
* Return a decimal as string to be written to the database.
19+
* Get all of the current attributes on the model for an insert operation.
1920
*
20-
* @see \Illuminate\Database\Eloquent\Concerns\HasAttributes::asDecimal
21+
* @return array<mixed>
22+
*/
23+
protected function getAttributesForInsert()
24+
{
25+
$attributes = parent::getAttributes();
26+
27+
foreach ($attributes as $key => $value) {
28+
if ($value instanceof Decimal) {
29+
$attributes[$key] = $this->toString($key, $value);
30+
}
31+
}
32+
33+
return $attributes;
34+
}
35+
36+
/**
37+
* Determine if the new and old values for a given key are equivalent.
2138
*
22-
* @param Decimal $value
23-
* @param int $decimals
39+
* @param string $key
2440
*
25-
* @return \Decimal\Decimal
41+
* @return bool
2642
*/
27-
protected function asDecimal($value, $decimals)
43+
public function originalIsEquivalent($key)
44+
{
45+
$castTypeIsDecimal = false;
46+
$casts = $this->getCasts();
47+
if (array_key_exists($key, $casts)) {
48+
$castTypeIsDecimal = $this->isDecimalCast($casts[$key]);
49+
}
50+
51+
$attribute = $this->attributes[$key] ?? null;
52+
$original = $this->original[$key] ?? null;
53+
54+
if (!$castTypeIsDecimal && !$attribute instanceof Decimal && !$original instanceof Decimal) {
55+
return parent::originalIsEquivalent($key);
56+
}
57+
58+
if ($attribute instanceof Decimal) {
59+
$attribute = $this->toString($key, $attribute);
60+
}
61+
if ($original instanceof Decimal) {
62+
$original = $this->toString($key, $original);
63+
}
64+
65+
return $attribute === $original;
66+
}
67+
68+
private function toString(string $key, Decimal $value): string
2869
{
29-
assert($value instanceof Decimal);
30-
31-
return $value->toFixed($decimals, $commas = false, PHP_ROUND_HALF_UP);
70+
$casts = $this->getCasts();
71+
if (!array_key_exists($key, $casts)) {
72+
return (string)$value;
73+
}
74+
75+
$castType = $casts[$key];
76+
if (!$this->isDecimalCast($castType)) {
77+
return $value;
78+
}
79+
80+
$decimals = explode(':', $castType)[1];
81+
82+
return $value->toFixed($decimals, false, PHP_ROUND_HALF_UP);
83+
}
84+
85+
/**
86+
* Cast an attribute to a native PHP type.
87+
*
88+
* @see \Illuminate\Database\Eloquent\Concerns\HasAttributes::castAttribute
89+
*
90+
* @param string $key
91+
* @param mixed $value Raw value
92+
*
93+
* @return mixed Transformed value
94+
*/
95+
protected function castAttribute($key, $value)
96+
{
97+
if ($value !== null) {
98+
$casts = $this->getCasts();
99+
if (array_key_exists($key, $casts)) {
100+
$castType = $casts[$key];
101+
if ($this->isDecimalCast($castType)) {
102+
$precision = explode(':', $castType)[2] ?? Decimal::DEFAULT_PRECISION;
103+
104+
return new Decimal($value, $precision);
105+
}
106+
}
107+
}
108+
109+
return parent::castAttribute($key, $value);
32110
}
33111
}

0 commit comments

Comments
 (0)