It is possible to nest multiple data objects:
class ArtistData extends Data
{
public function __construct(
public string $name,
public int $age,
) {
}
}
class AlbumData extends Data
{
public function __construct(
public string $title,
public ArtistData $artist,
) {
}
}
You can now create a data object as such:
new AlbumData(
'Never gonna give you up',
new ArtistData('Rick Astley', 22)
);
Or you could create it from an array using a magic creation method:
AlbumData::from([
'title' => 'Never gonna give you up',
'artist' => [
'name' => 'Rick Astley',
'age' => 22
]
]);
##Collections of data objects
What if you want to nest a collection of data objects within a data object?
That's perfectly possible, but there's a small catch; you should always define what kind of data objects will be stored
within the collection. This is really important later on to create validation rules for data objects or partially
transforming data objects.
There are a few different ways to define what kind of data objects will be stored within a collection. You could use an
annotation, for example, which has an advantage that your IDE will have better suggestions when working with the data
object. And as an extra benefit, static analyzers like PHPStan will also be able to detect errors when your code
is using the wrong types.
A collection of data objects defined by annotation looks like this:
class AlbumData extends Data
{
public function __construct(
public string $title,
public array $songs,
) {
}
}
or like this when using properties:
class AlbumData extends Data
{
public string $title;
public array $songs;
}
If you've imported the data class you can use the short notation:
use App\Data\SongData;
class AlbumData extends Data
{
public array $songs;
}
It is also possible to use generics:
use App\Data\SongData;
class AlbumData extends Data
{
public array $songs;
}
The same is true for Laravel collections, but be sure to use two generic parameters to describe the collection. One for the collection key type and one for the data object type.
use App\Data\SongData;
use Illuminate\Support\Collection;
class AlbumData extends Data
{
public Collection $songs;
}
You can also use an attribute to define the type of data objects that will be stored within a collection:
class AlbumData extends Data
{
public function __construct(
public string $title,
#[DataCollectionOf(SongData::class)]
public array $songs,
) {
}
}
This was the old way to define the type of data objects that will be stored within a collection. It is still supported, but we recommend using the annotation.