Skip to content

Commit

Permalink
Allow use DTO with default values when null database value (#13)
Browse files Browse the repository at this point in the history
* add ability to instantiate caster with null values by specifying nullable cast parameter

* Increase minimum Spatie DTO version

Co-authored-by: Jess Archer <jess@jessarcher.com>
  • Loading branch information
daraghoshea and jessarcher authored Apr 25, 2022
1 parent 2ca7539 commit e875ff8
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 2 deletions.
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,40 @@ $user->address->calculateDistance($otherUser->address);
echo (string) $user->address;
```


### Using defaults for null database values

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.

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.

```php
namespace App\Models;

use App\Values\Address;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
protected $casts = [
'settings' => Settings::class . ':nullable',
];
}
```

This will ensure that the `Settings` caster is instantiated even when the `settings` column in the database is `null`.

You may then specify some default values in the cast which will be used instead.

```php
use JessArcher\CastableDataTransferObject\CastableDataTransferObject;

class Settings extends CastableDataTransferObject
{
public string $title = 'Default';
}
```

### Controlling serialization

You may provide the caster with flags to be used for serialization by adding the `CastUsingJsonFlags` attribute to your object:
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"require": {
"php": "^8.0",
"illuminate/contracts": "^8.0|^9.0",
"spatie/data-transfer-object": "^3.0",
"spatie/data-transfer-object": "^3.0.4",
"thecodingmachine/safe": "^1.3|^2.0"
},
"require-dev": {
Expand Down
2 changes: 1 addition & 1 deletion src/CastableDataTransferObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ abstract class CastableDataTransferObject extends DataTransferObject implements
{
public static function castUsing(array $arguments)
{
return new DataTransferObjectCast(static::class);
return new DataTransferObjectCast(static::class, $arguments);
}

public function toJson($options = 0)
Expand Down
6 changes: 6 additions & 0 deletions src/Casts/DataTransferObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ class DataTransferObject implements CastsAttributes
public function __construct(
/** @var string The DataTransferObject class to cast to */
protected string $class,
/** @var array The cast parameters specified */
protected array $parameters = [],
) {
}

Expand All @@ -20,6 +22,10 @@ public function __construct(
*/
public function get($model, string $key, $value, array $attributes)
{
if (is_null($value) && in_array('nullable', $this->parameters)) {
$value = '{}';
}

if (is_null($value)) {
return;
}
Expand Down
17 changes: 17 additions & 0 deletions tests/CastableDataTransferObjectTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,17 @@ public function cast_uses_specified_flags_for_data_transfer_objects()
$this->assertSame('{"floatValue":52.0}', $user->with_flags);
$this->assertSame('{"floatValue":20}', $user->without_flags);
}

/** @test */
public function it_passes_null_values_to_caster_when_nullable_cast_attribute_present()
{
$user = User::factory()->create(['settings' => null]);

$this->assertDatabaseHas('users', ['settings' => null]);

$this->assertInstanceOf(Settings::class, $user->refresh()->settings);
$this->assertEquals('Default', $user->settings->title);
}
}

class Address extends CastableDataTransferObject
Expand All @@ -147,6 +158,11 @@ class DataTransferObjectWithoutFlags extends CastableDataTransferObject
public float $floatValue;
}

class Settings extends CastableDataTransferObject
{
public string $title = 'Default';
}

class User extends Model
{
use HasFactory;
Expand All @@ -155,6 +171,7 @@ class User extends Model
'address' => Address::class,
'with_flags' => DataTransferObjectWithFlags::class,
'without_flags' => DataTransferObjectWithoutFlags::class,
'settings' => Settings::class . ':nullable',
];

protected static function newFactory()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public function up()
$table->jsonb('address')->nullable();
$table->jsonb('with_flags')->nullable();
$table->jsonb('without_flags')->nullable();
$table->jsonb('settings')->nullable();
$table->timestamps();
});
}
Expand Down

0 comments on commit e875ff8

Please sign in to comment.