Skip to content
This repository was archived by the owner on Mar 3, 2025. It is now read-only.

Commit e875ff8

Browse files
Allow use DTO with default values when null database value (#13)
* add ability to instantiate caster with null values by specifying nullable cast parameter * Increase minimum Spatie DTO version Co-authored-by: Jess Archer <[email protected]>
1 parent 2ca7539 commit e875ff8

6 files changed

+60
-2
lines changed

README.md

+34
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,40 @@ $user->address->calculateDistance($otherUser->address);
9393
echo (string) $user->address;
9494
```
9595

96+
97+
### Using defaults for null database values
98+
99+
By default, if a database value is `null`, then the model attribute will also be `null`. However, sometimes you might want to instantiate the attribute with some default values.
100+
101+
To achieve this, you may provide an additional `nullable` [Cast Parameter](https://laravel.com/docs/eloquent-mutators#cast-parameters) to ensure the caster gets instantiated.
102+
103+
```php
104+
namespace App\Models;
105+
106+
use App\Values\Address;
107+
use Illuminate\Database\Eloquent\Model;
108+
109+
class User extends Model
110+
{
111+
protected $casts = [
112+
'settings' => Settings::class . ':nullable',
113+
];
114+
}
115+
```
116+
117+
This will ensure that the `Settings` caster is instantiated even when the `settings` column in the database is `null`.
118+
119+
You may then specify some default values in the cast which will be used instead.
120+
121+
```php
122+
use JessArcher\CastableDataTransferObject\CastableDataTransferObject;
123+
124+
class Settings extends CastableDataTransferObject
125+
{
126+
public string $title = 'Default';
127+
}
128+
```
129+
96130
### Controlling serialization
97131

98132
You may provide the caster with flags to be used for serialization by adding the `CastUsingJsonFlags` attribute to your object:

composer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
"require": {
2525
"php": "^8.0",
2626
"illuminate/contracts": "^8.0|^9.0",
27-
"spatie/data-transfer-object": "^3.0",
27+
"spatie/data-transfer-object": "^3.0.4",
2828
"thecodingmachine/safe": "^1.3|^2.0"
2929
},
3030
"require-dev": {

src/CastableDataTransferObject.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ abstract class CastableDataTransferObject extends DataTransferObject implements
1414
{
1515
public static function castUsing(array $arguments)
1616
{
17-
return new DataTransferObjectCast(static::class);
17+
return new DataTransferObjectCast(static::class, $arguments);
1818
}
1919

2020
public function toJson($options = 0)

src/Casts/DataTransferObject.php

+6
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ class DataTransferObject implements CastsAttributes
1212
public function __construct(
1313
/** @var string The DataTransferObject class to cast to */
1414
protected string $class,
15+
/** @var array The cast parameters specified */
16+
protected array $parameters = [],
1517
) {
1618
}
1719

@@ -20,6 +22,10 @@ public function __construct(
2022
*/
2123
public function get($model, string $key, $value, array $attributes)
2224
{
25+
if (is_null($value) && in_array('nullable', $this->parameters)) {
26+
$value = '{}';
27+
}
28+
2329
if (is_null($value)) {
2430
return;
2531
}

tests/CastableDataTransferObjectTest.php

+17
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,17 @@ public function cast_uses_specified_flags_for_data_transfer_objects()
127127
$this->assertSame('{"floatValue":52.0}', $user->with_flags);
128128
$this->assertSame('{"floatValue":20}', $user->without_flags);
129129
}
130+
131+
/** @test */
132+
public function it_passes_null_values_to_caster_when_nullable_cast_attribute_present()
133+
{
134+
$user = User::factory()->create(['settings' => null]);
135+
136+
$this->assertDatabaseHas('users', ['settings' => null]);
137+
138+
$this->assertInstanceOf(Settings::class, $user->refresh()->settings);
139+
$this->assertEquals('Default', $user->settings->title);
140+
}
130141
}
131142

132143
class Address extends CastableDataTransferObject
@@ -147,6 +158,11 @@ class DataTransferObjectWithoutFlags extends CastableDataTransferObject
147158
public float $floatValue;
148159
}
149160

161+
class Settings extends CastableDataTransferObject
162+
{
163+
public string $title = 'Default';
164+
}
165+
150166
class User extends Model
151167
{
152168
use HasFactory;
@@ -155,6 +171,7 @@ class User extends Model
155171
'address' => Address::class,
156172
'with_flags' => DataTransferObjectWithFlags::class,
157173
'without_flags' => DataTransferObjectWithoutFlags::class,
174+
'settings' => Settings::class . ':nullable',
158175
];
159176

160177
protected static function newFactory()

tests/database/migrations/2014_10_12_000000_create_users_table.php

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public function up()
2323
$table->jsonb('address')->nullable();
2424
$table->jsonb('with_flags')->nullable();
2525
$table->jsonb('without_flags')->nullable();
26+
$table->jsonb('settings')->nullable();
2627
$table->timestamps();
2728
});
2829
}

0 commit comments

Comments
 (0)