Делал нечто подобное, получилось так:
namespace App\Doctor;
use App\Doctor\Check\CheckInterface;
final class Doctor
{
/**
* @var CheckInterface[]
*/
private iterable $checks;
public function __construct(iterable $checks)
{
$this->checks = $checks;
}
/**
* @return Violation[]|array
*/
public function check(): array
{
$violations = [];
foreach ($this->checks as $check) {
$violations[$check->feature()] = array_merge($violations[$check->feature()] ?? [], $check->violations());
}
return $violations;
}
}
namespace App\Doctor\Check;
use App\Doctor\Violation;
interface CheckInterface
{
public function feature(): string;
/**
* @return Violation[]
*/
public function violations(): array;
}
services:
_instanceof:
App\Doctor\Check\CheckInterface:
tags:
- { name: app.doctor.check }
App\Doctor\Doctor:
arguments:
$checks: !tagged app.doctor.check
public function doctorAction(): JsonResponse
{
return $this->json($this->doctor->check());
}
{
"foo": [], // Ok
"bar": [
{ "message": "Отсутствуют статусы", "treatment": "Добавьте статусы" }
]
}
Как вариант, можно группировать проверки по фичам, чтоб не проверять все, когда нужна информация по конкретной фиче, но для этого надо будет CompilerPass заюзать