Casts take simple values and cast them into complex types. For example, 16-05-1994T00:00:00+00
could be cast into a Carbon
object with the same date.
A cast implements the following interface:
interface Cast
{
public function cast(DataProperty $property, mixed $value, array $properties, CreationContext $context): mixed;
}
A cast receives the following:
-
property a
DataProperty
object which represents the property for which the value is cast. You can read more about the internal structures of the package here
-
value the value that should be cast
-
properties an array of the current properties that will be used to create the data object
-
creationContext the context in which the data object is being created you'll find the following info here:
-
dataClass the data class which is being created
-
validationStrategy the validation strategy which is being used
-
mapPropertyNames whether property names should be mapped
-
disableMagicalCreation whether to use the magical creation methods or not
-
ignoredMagicalMethods the magical methods which are ignored
-
casts a collection of global casts
In the end, the cast should return a casted value.
When the cast is unable to cast the value, an Uncastable
object should be returned.
A cast like a transformer never receives a null
value, this is because the package will always keep a null
value as null
because we don't want to create values out of thin air. If you want to replace a null
value, then use a magic method.
##Castables
You may want to allow your application's value objects to define their own custom casting logic. Instead of attaching the custom cast class to your object, you may alternatively attach a value object class that implements the Spatie\LaravelData\Casts\Castable
interface:
class ForgotPasswordRequest extends Data
{
public function __construct(
#[WithCastable(Email::class)]
public Email $email,
) {
}
}
When using Castable
classes, you may still provide arguments in the WithCastable
attribute. The arguments will be passed to the dataCastUsing
method:
class DuplicateEmailCheck extends Data
{
public function __construct(
#[WithCastable(Email::class, normalize: true)]
public Email $email,
) {
}
}
By combining "castables" with PHP's anonymous classes, you may define a value object and its casting logic as a single castable object. To accomplish this, return an anonymous class from your value object's dataCastUsing
method. The anonymous class should implement the Cast
interface:
<?php
namespace Spatie\LaravelData\Tests\Fakes\Castables;
use Spatie\LaravelData\Casts\Cast;
use Spatie\LaravelData\Casts\Castable;
use Spatie\LaravelData\Support\Creation\CreationContext;
use Spatie\LaravelData\Support\DataProperty;
class Email implements Castable
{
public function __construct(public string $email) {
}
public static function dataCastUsing(...$arguments): Cast
{
return new class implements Cast {
public function cast(DataProperty $property, mixed $value, array $properties, CreationContext $context): mixed
return new Email($value);
}
};
}
}
##Casting iterable values
We saw earlier that you can cast all sorts of values in an array or Collection which are not data objects, for this to work, you should implement the IterableItemCast
interface:
interface IterableItemCast
{
public function castIterableItem(DataProperty $property, mixed $value, array $properties, CreationContext $context): mixed;
}
The castIterableItem
method is called for each item in an array or Collection when being cast, you can check the iterableItemType
property of DataPorperty->Type
to get the type the items should be transformed into.
##Combining casts and transformers
You can combine casts and transformers in one class:
class ToUpperCastAndTransformer implements Cast, Transformer
{
public function cast(DataProperty $property, mixed $value, array $properties, CreationContext $context): string
{
return strtoupper($value);
}
public function transform(DataProperty $property, mixed $value, TransformationContext $context): string
{
return strtoupper($value);
}
}
Within your data object, you can use the WithCastAndTransformer
attribute to use the cast and transformer:
class SongData extends Data
{
public function __construct(
public string $title,
#[WithCastAndTransformer(SomeCastAndTransformer::class)]
public string $artist,
) {
}
}