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

A Custom Output Without an Entity

A Custom Output Without an Entity

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

Chapter 5 ALREADY showed an ApiResource WITHOUT a Doctrine entity as a "hello world" example – this chapter goes FURTHER: a REAL, USEFUL statistics resource that delivers EXCLUSIVELY computed data.

Defining a statistics ApiResource

api/src/ApiResource/DashboardStatistics.php
<?php

declare(strict_types=1);

namespace App\ApiResource;

use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use App\State\DashboardStatisticsProvider;

#[ApiResource(
    operations: [
        new Get(
            uriTemplate: '/dashboard/statistics',
            provider: DashboardStatisticsProvider::class,
        ),
    ]
)]
final class DashboardStatistics
{
    public int $totalProjects;
    public int $totalTasks;
    public int $completedTasks;
    public float $completionRate;
}

EXACTLY like Begruessung from chapter 5: a SIMPLE PHP class WITHOUT an #[ORM\Entity] attribute, in the src/ApiResource/ directory instead of src/Entity/ – a common convention to DISTINGUISH non-persistent resources from REAL entities.

Implementing the provider

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

declare(strict_types=1);

namespace App\State;

use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface;
use App\ApiResource\DashboardStatistics;
use App\Repository\ProjectRepository;
use App\Repository\TaskRepository;

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

    public function provide(Operation $operation, array $uriVariables = [], array $context = []): DashboardStatistics
    {
        $totalTasks = $this->taskRepository->count([]);
        $completedTasks = $this->taskRepository->count(['done' => true]);

        $stats = new DashboardStatistics();
        $stats->totalProjects = $this->projectRepository->count([]);
        $stats->totalTasks = $totalTasks;
        $stats->completedTasks = $completedTasks;
        $stats->completionRate = $totalTasks > 0
            ? round($completedTasks / $totalTasks * 100, 1)
            : 0.0;

        return $stats;
    }
}

count([]) uses the EFFICIENT COUNT(*) database query from Doctrine's ServiceEntityRepository, instead of (as in chapter 59, deliberately simplified for didactic reasons) loading an ENTIRE collection.

Testing the endpoint

curl -k https://localhost/api/dashboard/statistics -H "Authorization: Bearer $TOKEN"
{
  "totalProjects": 45,
  "totalTasks": 128,
  "completedTasks": 67,
  "completionRate": 52.3
}

Tipp: The Swagger UI entry for this resource appears AUTOMATICALLY, EXACTLY as for ANY other #[ApiResource] – from a documentation/client perspective, it is IRRELEVANT whether a Doctrine entity or a plain PHP class is behind it.