hrabo / symfony-ares
Symfony 7+ bundle for the Czech ARES (ARES2) REST API: PSR-18 client, search + detail endpoints, retry, endpoint failover, optional cache and rate limiting.
Installs: 0
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
Type:symfony-bundle
pkg:composer/hrabo/symfony-ares
Requires
- php: ^8.2
- ext-json: *
- nyholm/psr7: ^1.8
- psr/http-client: ^1.0
- psr/http-factory: ^1.0
- psr/http-message: ^1.1 || ^2.0
- psr/log: ^1.1 || ^2.0 || ^3.0
- psr/simple-cache: ^1.0 || ^2.0 || ^3.0
- symfony/cache: ^7.0
- symfony/framework-bundle: ^7.0
- symfony/http-client: ^7.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.60
- phpstan/phpstan: ^1.11
- phpunit/phpunit: ^11.0
This package is auto-updated.
Last update: 2026-02-21 11:10:36 UTC
README
Symfony 7+ bundle for the Czech ARES (ARES2) REST API.
It provides:
Hrabo\SymfonyAres\AresClient– low-level client returning raw ARES payloadsHrabo\SymfonyAres\Application\EconomicSubjectService– typed/DDD-friendly facadeHrabo\SymfonyAres\Application\AresLustrationService– multi-source “lustration” orchestrator
Built-in resilience & safeguards:
- Exponential backoff retries (429/5xx by default)
- Client-side base URI failover (round-robin + cooldown)
- Optional PSR-16 cache for GET endpoints (via Symfony Cache)
- Optional in-memory fixed-window rate limiter
Install
composer require hrabo/symfony-ares
If Symfony Flex doesn’t auto-enable the bundle, add it manually:
// config/bundles.php return [ // ... Hrabo\SymfonyAres\HraboAresBundle::class => ['all' => true], ];
Configuration
Create config/packages/hrabo_ares.yaml:
hrabo_ares: base_uri: 'https://ares.gov.cz/ekonomicke-subjekty-v-be/rest/' # Optional list for client-side failover / load balancing base_uris: [] endpoint_cooldown_seconds: 10 search_path: 'ekonomicke-subjekty/vyhledat' default_headers: User-Agent: 'my-app/1.0 (+https://example.com)' cache: enabled: true pool: 'cache.app' ttl_seconds: 300 rate_limit: enabled: false key: 'ares2' max_requests: 450 window_seconds: 60 retry: max_retries: 2 base_delay_ms: 200 max_delay_ms: 2000 jitter: 0.2 retry_http_status_codes: [429, 500, 502, 503, 504]
Usage
Low-level client (raw ARES payloads)
use Hrabo\SymfonyAres\AresClient; use Hrabo\SymfonyAres\DTO\Pagination; use Hrabo\SymfonyAres\DTO\SearchRequest; final class AresDemo { public function __construct(private AresClient $ares) {} public function run(): void { $detail = $this->ares->getEconomicSubject('00006947'); $res = $this->ares->searchEconomicSubjects(new SearchRequest( criteria: ['obchodniJmeno' => 'Ministerstvo financí'], pagination: new Pagination(start: 0, count: 10), sort: [], )); // $detail is array<string,mixed> // $res->items is list<array<string,mixed>> } }
Typed API (DDD-friendly)
use Hrabo\SymfonyAres\Application\EconomicSubjectService; use Hrabo\SymfonyAres\DTO\Pagination; final class SubjectDemo { public function __construct(private EconomicSubjectService $subjects) {} public function run(): void { $subject = $this->subjects->getByIco('00006947'); $result = $this->subjects->search( ['obchodniJmeno' => 'Ministerstvo'], new Pagination(0, 20), ); foreach ($result->items as $item) { echo (string) $item->ico . ' ' . ($item->name ?? '') . PHP_EOL; } } }
Lustration (multi-source due diligence)
use Hrabo\SymfonyAres\Application\AresLustrationService; use Hrabo\SymfonyAres\DTO\Lustration\LustrationOptions; use Hrabo\SymfonyAres\DTO\Lustration\LustrationQuery; final class LustrationDemo { public function __construct(private AresLustrationService $lustration) {} public function run(): void { $result = $this->lustration->run( LustrationQuery::forCompanyName('Ministerstvo financí'), new LustrationOptions( maxTargets: 5, relevantSourcesOnly: true, // uses CORE->seznamRegistraci to avoid needless 404s ) ); foreach ($result->subjects as $subject) { echo $subject->ico . PHP_EOL; foreach ($subject->bySource as $sourceKey => $sourceResult) { echo " - {$sourceKey}: {$sourceResult->status->value}" . PHP_EOL; } } } }
Person name search – important limitation
ARES CORE does not expose a public “person → companies” search across statutory bodies.
So LustrationQuery::forPersonName() is implemented as a best-effort OSVČ / name-as-trade-name lookup:
it tries a few obchodniJmeno variants like "Jan Novák", "Novák Jan", "Novák, Jan" and then proceeds with the same multi-source fetch.
If you need true person-to-company linking, you will need another legally available source (e.g. licensed commercial registry data) and treat ARES as a data enrichment layer.
License
MIT