Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Tiskiel's avatar

Wich best practice to use with DTO [ Spatie Laravel data ]?

Hi everyone,

I have a use case where I have two DTOs that share some of the same attributes and I'd like to extract them into the BaseData.

I've tried using extends but I'm a bit confused about using the parent constructor.

My question: Is it better to use extends or nesting?

Here's what I've got at the moment:


#[TypeScript]
class BasePreparationRevisionData extends Data
{
    public function __construct(
        public int $id,
        public ?string $order_number,
        public ?string $short_order_number,
        public ?string $name,
        public ?string $plan,
        public ?string $project,
        public DateTime $created_at,
        public DateTime $updated_at,
    ) {
    }
}

#[TypeScript]
class PreparationData extends BasePreparationRevisionData
{
    public function __construct(
        public int $order_position,
        /** @var DataCollection<MarkerData> $markers */
        public Lazy|DataCollection|Optional $markers,
        public Lazy|int|Optional $markers_count,
        public Lazy|int|Optional $marker_lines_count,
        public Lazy|int|Optional $marker_lines_finished_count,
        public ?PreparationMetaData $meta,
    ) {
        parent::__construct(
            -1,
            null,
            null,
            null,
            null,
            null,
            new DateTime,
            new DateTime
        );
    }
}

#[TypeScript]
class RevisionData extends BasePreparationRevisionData
{
    public function __construct(
        public ?bool $was_manipulated,
        /** @var string[]|null $changes */
        public ?array $changes,
        /** @var int[]|null */
        public ?array $new_operations,
        /** @var int[]|null */
        public ?array $deleted_operations,
        /** @var string[]|null $changes */
        public ?array $selected_actions,
        /** @var DataCollection<RevisionMarkerData> $revision_markers */
        public Lazy|DataCollection|Optional $revision_markers,
        public Lazy|int|Optional $revision_markers_count,
        public ?RevisionMetaData $meta,
    ) {
        parent::__construct(
            -1,
            null,
            null,
            null,
            null,
            null,
            new DateTime,
            new DateTime
        );
    }
}

I'm not sure that I use correctly the parent constructor. Like I use it, do I need add the parent attribute when I instance a new Preparation or a new Revision ?

For the nesting I've think to use it like this :

#[TypeScript]
class BaseData extends Data
{
    public function __construct(
        public int $id,
        public ?string $order_number,
        public ?string $short_order_number,
        public ?string $name,
        public ?string $plan,
        public ?string $project,
        public DateTime $created_at,
        public DateTime $updated_at,
    ) {
    }
}

#[TypeScript]
class PreparationData extends BasePreparationRevisionData
{
    public function __construct(
		public BaseData $baseData,
        public int $order_position,
        /** @var DataCollection<MarkerData> $markers */
        public Lazy|DataCollection|Optional $markers,
        public Lazy|int|Optional $markers_count,
        public Lazy|int|Optional $marker_lines_count,
        public Lazy|int|Optional $marker_lines_finished_count,
        public ?PreparationMetaData $meta,
    ) {
    }
}

What practice do you recommend ?

Thank you in advance

0 likes
0 replies

Please or to participate in this conversation.