Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

Completing the Promised DTO Example

Completing the Promised DTO Example

~15 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026

Chapter 27 showed ProjectSummary only as a CONCEPT, WITHOUT a working provider – WITH the knowledge from chapter 57, this can NOW be completed FULLY.

Fully defining the operation

use App\Dto\ProjectSummary;
use App\State\ProjectSummaryProvider;

new Get(
    uriTemplate: '/projects/{id}/summary',
    output: ProjectSummary::class,
    provider: ProjectSummaryProvider::class,
),

Implementing the provider

api/src/State/ProjectSummaryProvider.php
<?php

declare(strict_types=1);

namespace App\State;

use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface;
use App\Dto\ProjectSummary;
use App\Repository\ProjectRepository;

final class ProjectSummaryProvider implements ProviderInterface
{
    public function __construct(
        private readonly ProjectRepository $projectRepository,
    ) {
    }

    public function provide(Operation $operation, array $uriVariables = [], array $context = []): ?ProjectSummary
    {
        $project = $this->projectRepository->find($uriVariables['id']);

        if (null === $project) {
            return null;
        }

        $summary = new ProjectSummary();
        $summary->id = $project->getId();
        $summary->name = $project->getName();
        $summary->isRecent = $project->isRecent();
        $summary->taskCount = $project->getTasks()->count();
        $summary->openTaskCount = $project->getTasks()
            ->filter(fn ($task) => !$task->isDone())
            ->count();

        return $summary;
    }
}

$uriVariables['id'] contains the {id} placeholder from the uriTemplate – EXACTLY the mechanism from chapter 39, now evaluated MANUALLY instead of via Link, since ProjectSummary is NOT a Doctrine entity of its own.

Extending the DTO with the new fields

api/src/Dto/ProjectSummary.php
<?php

declare(strict_types=1);

namespace App\Dto;

final class ProjectSummary
{
    public int $id;
    public string $name;
    public bool $isRecent;
    public int $taskCount;
    public int $openTaskCount;
}

Testing the endpoint

curl -k https://localhost/api/projects/1/summary -H "Authorization: Bearer $TOKEN"
{
  "id": 1,
  "name": "Website Relaunch",
  "isRecent": true,
  "taskCount": 5,
  "openTaskCount": 3
}

A SINGLE endpoint that COMBINES data from MULTIPLE sources (Project fields PLUS computed task statistics) into ONE flat response – EXACTLY the use case chapter 27 NAMED as the reason for DTOs instead of groups.

Achtung: getTasks()->count() loads the ENTIRE tasks collection from the database, JUST to COUNT it – with MANY tasks, a dedicated COUNT query (via the repository) would be MORE EFFICIENT. For OUR learning example, the SIMPLE variant deliberately stays as is.

Tipp: THIS chapter closes the loop left open in chapter 27 – a GOOD example of how this course DELIBERATELY forward-references and COMPLETES LATER, instead of explaining every concept IMMEDIATELY down to the last detail.