h4kuna/ares
h4kuna/ares is a PHP client for the Czech ARES business registry. Look up companies by IČO and retrieve structured details such as name, address, legal form, and registration data. Lightweight, framework-agnostic, and easy to integrate into Laravel or any PHP app.
Install the package:
composer require h4kuna/ares
There is no Laravel service provider, facade, or config file — this is a framework-agnostic library. First thing to do is open the README on GitHub and look at how the current major version constructs Ares / AresFactory, because the constructor changed between v2 and v3 (v3 requires you to pass a PSR-18 HTTP client and PSR-17 request factory, v2 used its own client). That one detail determines how you wire it up.
The minimal wiring in a Laravel app — a singleton in AppServiceProvider:
// app/Providers/AppServiceProvider.php
use h4kuna\Ares\Ares;
public function register(): void
{
$this->app->singleton(Ares::class, function () {
return new Ares(); // or new AresFactory()->create() depending on version
});
}
First use case: company auto-fill on registration. A Czech user types their IČO (8-digit company ID), your controller calls ARES, and populates name, address, and DIČ:
public function lookup(Ares $ares, Request $request)
{
$ico = preg_replace('/\D/', '', $request->input('ico'));
$subject = $ares->find($ico);
return response()->json([
'name' => $subject->getName(),
'vat_id' => $subject->getVatId(), // null for non-VAT-payers
'address' => (string) $subject->getAddress(),
]);
}
Treat that as a starting skeleton and verify method names against the class you installed — AresData/Subject/Address are the DTO types that come back, but property names have shifted across versions (getLegalForm, getRegistrationDate, getAddress()->getCity(), etc.).
Wrap it, don't sprinkle it. Because there's no facade, build one thin service in your app (App\Services\CompanyRegistry) that owns the ARES call plus validation, caching, and error normalization. Controllers, form requests, and Livewire components then depend on your class, which is swappable for a fake in tests. This is the single most valuable step for a package this small and version-churny.
Cache aggressively by IČO. ARES is a government SOAP/REST endpoint: it can take 1–3 seconds, occasionally times out, and returns identical data for the same IČO most days. Wrap the call:
return Cache::remember("ares:{$ico}", now()->addDay(), fn () => $this->ares->find($ico));
Company registry data doesn't need sub-hour freshness. A 6-hour or 24-hour TTL is standard.
Validate before you call. IČO is 8 digits with a weighted checksum. A local validator saves a round-trip and lets you reject junk input before hitting a public API:
// Roughly: last digit == 11 - ((sum of first 7 digits weighted 8..2) % 11) % 10
// Prefer a tested rule; e.g. composer require jakubboucek/lorem-ipsum? no — write it once and unit-test it.
Also normalize: strip spaces, zero-pad 7-digit historical IČOs to 8.
Use it as a Job, not a synchronous call in a form flow. When you need to refresh the ARES fields for stored customers (a nightly sync), push it to a queue. A single 500 ms call is fine in a request; 50 calls for a batch import will melt the request timeout. Rate-limit the queue (Bus::batch()->allowFailures()) and back off on failures.
Persist a snapshot, not a reference. ARES is the source of truth, but the response shape changes. When a user registers via your app, copy the relevant fields into your companies table alongside the IČO and a fetched_at column. Don't re-fetch on every page render, and don't store the returned DTO — it isn't a persisted value object.
Testing pattern. Never call ARES in CI. Bind a fake Ares implementation (or Mockery with a canned AresData) in the test setup. If you need realistic fixtures, capture responses from real IČOs like 27082440 (Alza.cz) and 45274649 (Seznam.cz) once and store them as fixtures.
config/ares.php to publish. Bind it yourself.getVatId() returns null for non-registered VAT payers (many sole traders). Don't call ->getVatId() in a string concatenation without a null check, and don't use VAT lookup as your primary identity — IČO is.null. The address DTO is flat and untyped-by-contract; a foreign-registered branch may have a country but no street. Guard each getter, or cast the whole thing to a string with a fallback.fyzická osoba) are hit-or-miss. Some individuals with an IČO do not have an ARES record worth using (no trade name, no getLegalForm). If your product needs to support them, provide a manual-entry fallback rather than blocking registration on a lookup failure.(new AresFactory())->create() is the quick fix, or bind a Guzzle/php-http adapter. Pin the version in composer.json and read the CHANGELOG before upgrading.Http\Client\Exception (or AresException for API-level errors). Wrap the call in a try/catch inside your service and convert to your own domain exception or null. Otherwise a transient ARES outage turns into a 500 on your signup form.RetryMiddleware, a logged psr18 client, etc.) rather than patching the library.How can I help you explore Laravel packages today?