Open
Description
✏️ Describe the bug
When I call the except
or only
methods on a data object using the default Data
cast, these filters do not persist.
In the first call to the cast, everything works as expected ✅:
{
"address": {
"country": "Greece",
"city": "Lynchfurt",
"street": "Vernice Stravenue",
"postalCode": "58391-3431",
"phone": "+1 (662) 664-1742",
"email": "[email protected]",
"comment": "Et omnis sit et asperiores voluptas. Architecto omnis ut amet velit quia id. Vero sit recusandae porro omnis incidunt molestiae ea."
}
}
DataEloquentCast.php:78, Spatie\LaravelData\Support\EloquentCasts\DataEloquentCast->set()
HasAttributes.php:1235, Illuminate\Database\Eloquent\Model->setClassCastableAttribute()
HasAttributes.php:1075, Illuminate\Database\Eloquent\Model->setAttribute()
Model.php:589, Illuminate\Database\Eloquent\Model->fill()
Model.php:683, Illuminate\Database\Eloquent\Model->newInstance()
Builder.php:1717, Illuminate\Database\Eloquent\Builder->newModelInstance()
Builder.php:1188, Illuminate\Database\Eloquent\Builder->create()
ForwardsCalls.php:23, Illuminate\Database\Eloquent\Model->forwardCallTo()
Model.php:2496, Illuminate\Database\Eloquent\Model->__call()
Model.php:2512, Illuminate\Database\Eloquent\Model::__callStatic()
web.php:27, Illuminate\Routing\RouteFileRegistrar->{closure:}()
But on the second call, the result is no longer as expected ❌:
{
"profile": "Maverick Cartwright",
"address": {
"country": "Greece",
"city": "Lynchfurt",
"street": "Vernice Stravenue",
+ "houseNumber": "09-18-560",
"postalCode": "58391-3431",
"phone": "+1 (662) 664-1742",
"email": "[email protected]",
"comment": "Et omnis sit et asperiores voluptas. Architecto omnis ut amet velit quia id. Vero sit recusandae porro omnis incidunt molestiae ea."
}
}
DataEloquentCast.php:78, Spatie\LaravelData\Support\EloquentCasts\DataEloquentCast->set()
+ HasAttributes.php:1899, Illuminate\Database\Eloquent\Model->mergeAttributesFromClassCasts()
+ HasAttributes.php:1881, Illuminate\Database\Eloquent\Model->mergeAttributesFromCachedCasts()
Model.php:1191, Illuminate\Database\Eloquent\Model->save()
Builder.php:1189, Illuminate\Database\Eloquent\Builder->{closure}()
helpers.php:399, tap()
Builder.php:1188, Illuminate\Database\Eloquent\Builder->create()
ForwardsCalls.php:23, Illuminate\Database\Eloquent\Model->forwardCallTo()
Model.php:2496, Illuminate\Database\Eloquent\Model->__call()
Model.php:2512, Illuminate\Database\Eloquent\Model::__callStatic()
web.php:27, Illuminate\Routing\RouteFileRegistrar->{closure:}()
Then again, the third call still behaves incorrectly ❌:
{
"profile": "Maverick Cartwright",
"address": {
"country": "Greece",
"city": "Lynchfurt",
"street": "Vernice Stravenue",
+ "houseNumber": "09-18-560",
"postalCode": "58391-3431",
"phone": "+1 (662) 664-1742",
"email": "[email protected]",
"comment": "Et omnis sit et asperiores voluptas. Architecto omnis ut amet velit quia id. Vero sit recusandae porro omnis incidunt molestiae ea."
}
}
DataEloquentCast.php:78, Spatie\LaravelData\Support\EloquentCasts\DataEloquentCast->set()
+ HasAttributes.php:1899, Illuminate\Database\Eloquent\Model->mergeAttributesFromClassCasts()
+ HasAttributes.php:1881, Illuminate\Database\Eloquent\Model->mergeAttributesFromCachedCasts()
HasAttributes.php:1950, Illuminate\Database\Eloquent\Model->getAttributes()
HasAttributes.php:2214, Illuminate\Database\Eloquent\Model->getDirty()
HasAttributes.php:2134, Illuminate\Database\Eloquent\Model->isDirty()
HasTimestamps.php:68, Illuminate\Database\Eloquent\Model->updateTimestamps()
Model.php:1366, Illuminate\Database\Eloquent\Model->performInsert()
Model.php:1214, Illuminate\Database\Eloquent\Model->save()
Builder.php:1189, Illuminate\Database\Eloquent\Builder->{closure}()
helpers.php:399, tap()
Builder.php:1188, Illuminate\Database\Eloquent\Builder->create()
ForwardsCalls.php:23, Illuminate\Database\Eloquent\Model->forwardCallTo()
Model.php:2496, Illuminate\Database\Eloquent\Model->__call()
Model.php:2512, Illuminate\Database\Eloquent\Model->__callStatic()
web.php:27, Illuminate\Routing\RouteFileRegistrar->{closure:}()
↪️ To Reproduce
UserProfileData.php
class UserProfileData extends Data
{
public function __construct(
public readonly string $profile,
public readonly AddressData $address,
)
{
$this->address->except('houseNumber'); // <-- here
}
}
We are trying to exclude
address.houseNumber
here.
AddressData.php
class AddressData extends Data
{
public function __construct(
public readonly string $country,
public readonly string $city,
public readonly string $street,
public readonly string $houseNumber,
public readonly string $postalCode,
public readonly string $phone,
public readonly string $email,
public readonly string $comment,
) {}
}
App\Models\User.php
class User extends Authenticatable
{
protected $fillable = [
'name',
'email',
'password',
+ 'profile',
];
protected function casts(): array
{
return [
'email_verified_at' => 'datetime',
'password' => 'hashed',
+ 'profile' => UserProfileData::class, // <-- here
];
}
}
routes/web.php
Route::get('/', function () {
$profile = \App\Data\UserProfileData::from([
'profile' => fake()->name,
'address' => [
'country' => fake()->country,
'city' => fake()->city,
'street' => fake()->streetName,
'houseNumber' => fake()->numerify('##-##-###'),
'postalCode' => fake()->postcode,
'phone' => fake()->phoneNumber,
'email' => fake()->email,
'comment' => fake()->text,
]
]);
$user_data = [
'email' => fake()->email,
'name' => fake()->name,
'password' => 123456,
];
$user = \App\Models\User::create($user_data + ['profile' => $profile]);
dump($user->toArray()); // Not Expected
dump($user->fresh()->toArray()); // Expected
});
Migration (SQLite)
Schema::table('users', function (Blueprint $table) {
$table->json('profile')->default('{}'); // using SQLite
});
✅ Expected Behavior
The inserted data should exclude address.houseNumber
:
{
"profile": "Miss Alysha Metz",
"address": {
"country": "Wallis and Futuna",
"city": "New Juniusview",
"street": "Breitenberg Flats",
"postalCode": "47876",
"phone": "1-458-927-1713",
"email": "[email protected]",
"comment": "Ex beatae minus ducimus animi. Odit ullam voluptatibus aliquam ducimus..."
}
}
❌ Actual Behavior
Instead, houseNumber
is still persisted:
{
"profile": "Miss Alysha Metz",
"address": {
"country": "Wallis and Futuna",
"city": "New Juniusview",
"street": "Breitenberg Flats",
+ "houseNumber": "29-92-219",
"postalCode": "47876",
"phone": "1-458-927-1713",
"email": "[email protected]",
"comment": "Ex beatae minus ducimus animi. Odit ullam voluptatibus aliquam ducimus..."
}
}
✅ However, when dumping the model (dump($user->fresh()->toArray())
), the houseNumber
is correctly excluded — indicating it's a problem at cast-to-database level, not in model access.
🖥️ Versions
- Laravel:
12.19.3
- Laravel Data:
4.17.0
- PHP:
8.4.4
Metadata
Metadata
Assignees
Labels
No labels