Skip to content

Commit 4431fb3

Browse files
[9.x] Support objects like GMP for custom Model casts (#43959)
* Use isset to support object like GMP * wip * Apply fixes from StyleCI * wip * wip * Update src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php Co-authored-by: StyleCI Bot <[email protected]>
1 parent 0efbd7e commit 4431fb3

File tree

3 files changed

+83
-6
lines changed

3 files changed

+83
-6
lines changed

.github/workflows/tests.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ jobs:
4949
uses: shivammathur/setup-php@v2
5050
with:
5151
php-version: ${{ matrix.php }}
52-
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, gd, redis-phpredis/[email protected], igbinary, msgpack, lzf, zstd, lz4, memcached
52+
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, gd, redis-phpredis/[email protected], igbinary, msgpack, lzf, zstd, lz4, memcached, gmp
5353
ini-values: error_reporting=E_ALL
5454
tools: composer:v2
5555
coverage: none
@@ -122,7 +122,7 @@ jobs:
122122
uses: shivammathur/setup-php@v2
123123
with:
124124
php-version: ${{ matrix.php }}
125-
extensions: dom, curl, libxml, mbstring, zip, pdo, sqlite, pdo_sqlite, gd, pdo_mysql, fileinfo, ftp, redis, memcached
125+
extensions: dom, curl, libxml, mbstring, zip, pdo, sqlite, pdo_sqlite, gd, pdo_mysql, fileinfo, ftp, redis, memcached, gmp
126126
tools: composer:v2
127127
coverage: none
128128

src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -289,11 +289,11 @@ protected function addCastAttributesToArray(array $attributes, array $mutatedAtt
289289
// If the attribute cast was a date or a datetime, we will serialize the date as
290290
// a string. This allows the developers to customize how dates are serialized
291291
// into an array without affecting how they are persisted into the storage.
292-
if ($attributes[$key] && in_array($value, ['date', 'datetime', 'immutable_date', 'immutable_datetime'])) {
292+
if (isset($attributes[$key]) && in_array($value, ['date', 'datetime', 'immutable_date', 'immutable_datetime'])) {
293293
$attributes[$key] = $this->serializeDate($attributes[$key]);
294294
}
295295

296-
if ($attributes[$key] && ($this->isCustomDateTimeCast($value) ||
296+
if (isset($attributes[$key]) && ($this->isCustomDateTimeCast($value) ||
297297
$this->isImmutableCustomDateTimeCast($value))) {
298298
$attributes[$key] = $attributes[$key]->format(explode(':', $value, 2)[1]);
299299
}
@@ -303,7 +303,7 @@ protected function addCastAttributesToArray(array $attributes, array $mutatedAtt
303303
$attributes[$key] = $this->serializeDate($attributes[$key]);
304304
}
305305

306-
if ($attributes[$key] && $this->isClassSerializable($key)) {
306+
if (isset($attributes[$key]) && $this->isClassSerializable($key)) {
307307
$attributes[$key] = $this->serializeClassCastableAttribute($key, $attributes[$key]);
308308
}
309309

@@ -930,7 +930,7 @@ public function setAttribute($key, $value)
930930
// If an attribute is listed as a "date", we'll convert it from a DateTime
931931
// instance into a form proper for storage on the database tables using
932932
// the connection grammar's date format. We will auto set the values.
933-
elseif ($value && $this->isDateAttribute($key)) {
933+
elseif (! is_null($value) && $this->isDateAttribute($key)) {
934934
$value = $this->fromDateTime($value);
935935
}
936936

tests/Integration/Database/EloquentModelCustomCastingTest.php

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
namespace Illuminate\Tests\Integration\Database;
44

5+
use GMP;
56
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
7+
use Illuminate\Contracts\Database\Eloquent\SerializesCastableAttributes;
68
use Illuminate\Database\Capsule\Manager as DB;
79
use Illuminate\Database\Eloquent\Model as Eloquent;
810
use Illuminate\Database\Schema\Blueprint;
@@ -40,6 +42,7 @@ public function createSchema()
4042
$table->increments('id');
4143
$table->string('address_line_one');
4244
$table->string('address_line_two');
45+
$table->integer('amount');
4346
$table->string('string_field');
4447
$table->timestamps();
4548
});
@@ -63,6 +66,7 @@ public function testSavingCastedAttributesToDatabase()
6366
/** @var \Illuminate\Tests\Integration\Database\CustomCasts $model */
6467
$model = CustomCasts::create([
6568
'address' => new AddressModel('address_line_one_value', 'address_line_two_value'),
69+
'amount' => gmp_init('1000', 10),
6670
'string_field' => null,
6771
]);
6872

@@ -72,6 +76,8 @@ public function testSavingCastedAttributesToDatabase()
7276
$this->assertSame('address_line_two_value', $model->getOriginal('address_line_two'));
7377
$this->assertSame('address_line_two_value', $model->getAttribute('address_line_two'));
7478

79+
$this->assertSame('1000', $model->getRawOriginal('amount'));
80+
7581
$this->assertNull($model->getOriginal('string_field'));
7682
$this->assertNull($model->getAttribute('string_field'));
7783
$this->assertSame('', $model->getRawOriginal('string_field'));
@@ -80,20 +86,23 @@ public function testSavingCastedAttributesToDatabase()
8086
$another_model = CustomCasts::create([
8187
'address_line_one' => 'address_line_one_value',
8288
'address_line_two' => 'address_line_two_value',
89+
'amount' => gmp_init('500', 10),
8390
'string_field' => 'string_value',
8491
]);
8592

8693
$this->assertInstanceOf(AddressModel::class, $another_model->address);
8794

8895
$this->assertSame('address_line_one_value', $model->address->lineOne);
8996
$this->assertSame('address_line_two_value', $model->address->lineTwo);
97+
$this->assertInstanceOf(GMP::class, $model->amount);
9098
}
9199

92100
public function testInvalidArgumentExceptionOnInvalidValue()
93101
{
94102
/** @var \Illuminate\Tests\Integration\Database\CustomCasts $model */
95103
$model = CustomCasts::create([
96104
'address' => new AddressModel('address_line_one_value', 'address_line_two_value'),
105+
'amount' => gmp_init('1000', 10),
97106
'string_field' => 'string_value',
98107
]);
99108

@@ -111,6 +120,7 @@ public function testInvalidArgumentExceptionOnNull()
111120
/** @var \Illuminate\Tests\Integration\Database\CustomCasts $model */
112121
$model = CustomCasts::create([
113122
'address' => new AddressModel('address_line_one_value', 'address_line_two_value'),
123+
'amount' => gmp_init('1000', 10),
114124
'string_field' => 'string_value',
115125
]);
116126

@@ -123,6 +133,27 @@ public function testInvalidArgumentExceptionOnNull()
123133
$this->assertSame('address_line_two_value', $model->address->lineTwo);
124134
}
125135

136+
public function testModelsWithCustomCastsCanBeConvertedToArrays()
137+
{
138+
/** @var \Illuminate\Tests\Integration\Database\CustomCasts $model */
139+
$model = CustomCasts::create([
140+
'address' => new AddressModel('address_line_one_value', 'address_line_two_value'),
141+
'amount' => gmp_init('1000', 10),
142+
'string_field' => 'string_value',
143+
]);
144+
145+
// Ensure model values remain unchanged
146+
$this->assertSame([
147+
'address_line_one' => 'address_line_one_value',
148+
'address_line_two' => 'address_line_two_value',
149+
'amount' => '1000',
150+
'string_field' => 'string_value',
151+
'updated_at' => $model->updated_at->toJSON(),
152+
'created_at' => $model->created_at->toJSON(),
153+
'id' => 1,
154+
], $model->toArray());
155+
}
156+
126157
/**
127158
* Get a database connection instance.
128159
*
@@ -188,6 +219,51 @@ public function set($model, $key, $value, $attributes)
188219
}
189220
}
190221

222+
class GMPCast implements CastsAttributes, SerializesCastableAttributes
223+
{
224+
/**
225+
* Cast the given value.
226+
*
227+
* @param \Illuminate\Database\Eloquent\Model $model
228+
* @param string $key
229+
* @param string $value
230+
* @param array $attributes
231+
* @return string|null
232+
*/
233+
public function get($model, $key, $value, $attributes)
234+
{
235+
return gmp_init($value, 10);
236+
}
237+
238+
/**
239+
* Prepare the given value for storage.
240+
*
241+
* @param \Illuminate\Database\Eloquent\Model $model
242+
* @param string $key
243+
* @param string|null $value
244+
* @param array $attributes
245+
* @return string
246+
*/
247+
public function set($model, $key, $value, $attributes)
248+
{
249+
return gmp_strval($value, 10);
250+
}
251+
252+
/**
253+
* Serialize the attribute when converting the model to an array.
254+
*
255+
* @param \Illuminate\Database\Eloquent\Model $model
256+
* @param string $key
257+
* @param mixed $value
258+
* @param array $attributes
259+
* @return mixed
260+
*/
261+
public function serialize($model, string $key, $value, array $attributes)
262+
{
263+
return gmp_strval($value, 10);
264+
}
265+
}
266+
191267
class NonNullableString implements CastsAttributes
192268
{
193269
/**
@@ -239,6 +315,7 @@ class CustomCasts extends Eloquent
239315
*/
240316
protected $casts = [
241317
'address' => AddressCast::class,
318+
'amount' => GMPCast::class,
242319
'string_field' => NonNullableString::class,
243320
];
244321
}

0 commit comments

Comments
 (0)