Skip to content

Commit bdb1244

Browse files
Merge branch 'serious-angel-main'
2 parents 7031924 + 1dc4df5 commit bdb1244

File tree

5 files changed

+166
-2
lines changed

5 files changed

+166
-2
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ coverage
88
.php_cs.cache
99
.php-cs-fixer.cache
1010
.phpunit.cache
11+
/.claude/

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,17 @@ class DateSettings extends Settings
588588

589589
The package will automatically find the cast and will use it to transform the types between the settings class and repository.
590590

591+
#### Available casts
592+
593+
The package comes with a few built-in casts:
594+
595+
- `DateTimeInterfaceCast` for objects implementing `DateTimeInterface` (`DateTime`, `DateTimeImmutable`, `Carbon`, `CarbonImmutable`)
596+
- `DateTimeZoneCast` for `DateTimeZone` objects
597+
- `DataCast` for `Spatie\LaravelData\Data` objects
598+
- `DataArrayCast` for arrays of `Spatie\LaravelData\Data` objects
599+
- `EnumCast` for native PHP enums
600+
- `CollectionCast` for `Illuminate\Support\Collection` objects
601+
591602
#### Typing properties
592603

593604
There are quite a few options to type properties. You could type them in PHP:
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
namespace Spatie\LaravelSettings\SettingsCasts;
4+
5+
use Spatie\LaravelData\Data;
6+
7+
class ArrayDataCast implements SettingsCast
8+
{
9+
protected DataCast $cast;
10+
11+
public function __construct(?string $type, bool|string $validate = false)
12+
{
13+
$this->cast = new DataCast($type, $validate);
14+
}
15+
16+
/**
17+
* @param array<array> $payload
18+
*
19+
* @return Data[]
20+
*/
21+
public function get($payload): array
22+
{
23+
return array_map(
24+
fn ($data) => $this->cast->get($data),
25+
$payload
26+
);
27+
}
28+
29+
/**
30+
* @param array<array|Data> $payload
31+
*
32+
* @return array<array>
33+
*/
34+
public function set($payload): array
35+
{
36+
return array_map(
37+
fn ($data) => $this->cast->set($data),
38+
$payload
39+
);
40+
}
41+
}

src/SettingsCasts/DataCast.php

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,29 @@
33
namespace Spatie\LaravelSettings\SettingsCasts;
44

55
use Exception;
6+
use Spatie\LaravelData\Contracts\BaseData;
67
use Spatie\LaravelData\Data;
78

89
class DataCast implements SettingsCast
910
{
1011
protected string $type;
1112

12-
public function __construct(?string $type)
13+
protected bool $validate;
14+
15+
public function __construct(?string $type, string|bool $validate = false)
1316
{
1417
$this->type = $this->ensureDataTypeExists($type);
18+
19+
$this->validate = is_string($validate)
20+
? in_array($validate, ['true', '1'], true)
21+
: $validate;
1522
}
1623

1724
public function get($payload): Data
1825
{
19-
return $this->type::from($payload);
26+
return $this->validate
27+
? $this->type::validateAndCreate($payload)
28+
: $this->type::from($payload);
2029
}
2130

2231
/**
@@ -39,6 +48,10 @@ protected function ensureDataTypeExists(?string $type): string
3948
throw new Exception("Cannot create a data cast for `{$type}` because the data does not exist");
4049
}
4150

51+
if (! class_implements($type, BaseData::class)) {
52+
throw new Exception("Cannot create a data cast for `$type` because the class does not implement data");
53+
}
54+
4255
return $type;
4356
}
4457
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
<?php
2+
3+
use Spatie\LaravelSettings\Migrations\SettingsBlueprint;
4+
use Spatie\LaravelSettings\Migrations\SettingsMigrator;
5+
use Spatie\LaravelSettings\Settings;
6+
use Spatie\LaravelSettings\SettingsCasts\ArrayDataCast;
7+
use Spatie\LaravelSettings\Tests\TestClasses\DummyData;
8+
9+
it('can save and retrieve an array of data objects', function () {
10+
$settingsClass = new class extends Settings {
11+
/** @var DummyData[] */
12+
public array $users;
13+
14+
public static function group(): string
15+
{
16+
return 'test_array_data';
17+
}
18+
19+
public static function casts(): array
20+
{
21+
return [
22+
'users' => ArrayDataCast::class . ':' . DummyData::class,
23+
];
24+
}
25+
};
26+
27+
resolve(SettingsMigrator::class)->inGroup('test_array_data', function (SettingsBlueprint $blueprint): void {
28+
$blueprint->add('users', [
29+
['name' => 'Freek'],
30+
['name' => 'Ruben'],
31+
]);
32+
});
33+
34+
$settings = resolve($settingsClass::class);
35+
36+
expect($settings->users)
37+
->toBeArray()
38+
->toHaveCount(2);
39+
40+
expect($settings->users[0])
41+
->toBeInstanceOf(DummyData::class)
42+
->name->toBe('Freek');
43+
44+
expect($settings->users[1])
45+
->toBeInstanceOf(DummyData::class)
46+
->name->toBe('Ruben');
47+
48+
$settings->users = [
49+
DummyData::from(['name' => 'Brent']),
50+
DummyData::from(['name' => 'Rias']),
51+
];
52+
53+
$settings->save();
54+
55+
$this->assertDatabaseHasSetting('test_array_data.users', [
56+
['name' => 'Brent'],
57+
['name' => 'Rias'],
58+
]);
59+
});
60+
61+
it('can save an array of data objects with validation', function () {
62+
$settingsClass = new class extends Settings {
63+
/** @var DummyData[] */
64+
public array $users;
65+
66+
public static function group(): string
67+
{
68+
return 'test_array_data_validated';
69+
}
70+
71+
public static function casts(): array
72+
{
73+
return [
74+
'users' => ArrayDataCast::class . ':' . DummyData::class . ',true',
75+
];
76+
}
77+
};
78+
79+
resolve(SettingsMigrator::class)->inGroup('test_array_data_validated', function (SettingsBlueprint $blueprint): void {
80+
$blueprint->add('users', [
81+
['name' => 'Freek'],
82+
]);
83+
});
84+
85+
$settings = resolve($settingsClass::class);
86+
87+
$settings->users = [
88+
DummyData::from(['name' => 'Brent']),
89+
DummyData::from(['name' => 'Rias']),
90+
];
91+
92+
$settings->save();
93+
94+
$this->assertDatabaseHasSetting('test_array_data_validated.users', [
95+
['name' => 'Brent'],
96+
['name' => 'Rias'],
97+
]);
98+
});

0 commit comments

Comments
 (0)