metaer/curl-wrapper-bundle
Symfony bundle that integrates the Metaer Curl Wrapper library, adding dependency-injection configuration and a ready-to-use HTTP client service for making cURL requests in PHP applications.
First, the framing problem: despite the name, this is a Symfony bundle, not a Laravel package. There is no service provider, no config/*.php publish, no facade, and no package auto-discovery. If you're a Laravel developer, "getting started" means deciding whether you actually need it — in 99% of greenfield Laravel work, Illuminate\Support\Facades\Http (Guzzle under the hood) already covers this ground with better ergonomics. You'd reach for this package only when you're maintaining a Symfony service inside a mixed codebase, or porting logic that already depends on its request/response shape.
What 1.0.6 changes for you: nothing functional. It is a one-line-ish deprecation fix — Alias::setPrivate() → setPublic() — aimed at silencing a notice introduced in symfony/dependency-injection 5.2. No new options, no API changes, no PHP or Symfony constraint bump announced. It is evidence of light maintenance, not a reason to adopt. Your adoption calculus is unchanged; only the "is this dead?" answer softens slightly.
Minimal steps (Symfony context):
composer require metaer/curl-wrapper-bundle
// config/bundles.php
Metaer\CurlWrapperBundle\CurlWrapperBundle::class => ['all' => true],
Then inject the bundle's client service into a controller/command and make one request.
Where to look first — in this order:
composer.json — PHP and symfony/framework-bundle constraints. Still the single most important file; the 1.0.6 fix targets the 5.2 line, so expect ^4|^5, not 6/7.src/DependencyInjection/Configuration.php — the config tree is the public contract. Every option you can set lives here; read it before reading the client class.src/DependencyInjection/*Extension.php and Resources/config/services.* — tells you the service ID to inject. This is also where the 1.0.6 alias change landed, so diff it if you were previously overriding the alias.CurlWrapper, Client, or similar) — method signatures and what a response looks like (raw string? decoded array? response object?).First use case: replace a hand-rolled curl_init / curl_setopt_array block with a single configured call — a GET to a third-party API with a timeout, an auth header, and JSON decoding handled in one place.
Wrap it, don't leak it. The most important pattern for a small, sparsely-maintained wrapper: put your own interface in front of it on day one.
interface RatesClient { public function rates(string $base): array; }
final class CurlWrapperRatesClient implements RatesClient
{
public function __construct(private object $curl) {} // the bundle service
public function rates(string $base): array
{
// adapt the bundle's call + decode shape here
}
}
This costs an hour and buys you the freedom to swap to Laravel's HTTP client later without touching call sites.
Config-driven per-API clients. Most curl wrapper bundles expose a global config (base URL, timeout, default headers, SSL options). If so, define one configured instance per upstream API rather than passing headers on every call — auth tokens and base URLs belong in config, not in controllers.
Standardize error handling at the boundary. cURL distinguishes transport failures (curl_errno) from HTTP failures (status ≥ 400). Old wrappers often collapse these or return false. Normalize both into your own exception type in the adapter, and log curl_error() alongside the URL — the raw message is frequently the only useful signal.
Use it in jobs, not controllers. Outbound HTTP is I/O; put it behind a queued job with retryUntil/backoff. This also insulates you from the bundle's timeout defaults, which are usually "none."
Pin the patch version. Since 1.0.6 is the first release in a long while, pin "metaer/curl-wrapper-bundle": "1.0.6" rather than floating — you don't want an unattended 1.0.7 changing alias visibility again mid-deploy.
Testing. Mock your RatesClient interface, not the bundle. If you must test the wrapper itself, check whether it accepts an injected handler or is final/static — many older wrappers are untestable by design.
Laravel wiring (if you insist). There's no bundle registration; you'll instantiate the client manually in a service provider:
$this->app->singleton(RatesClient::class, fn () => new CurlWrapperRatesClient(
new \Metaer\CurlWrapperBundle\...\Client($config)
));
Expect to reverse-engineer the constructor from services.yaml.
composer.json constraints before investing; if it pins symfony/framework-bundle: ^4|^5, that alone may kill the idea.Alias::setPublic() is the drop-in replacement for setPrivate(), but the observable effect is that the client alias becomes fetchable via $container->get(). Harmless for a HTTP client, but if you were relying on the service being private — or on compiler passes that only see private aliases — re-run your container build and check for changed service visibility after upgrading.CURLOPT_TIMEOUT / CURLOPT_CONNECTTIMEOUT, or whatever config keys map to them.CURLOPT_SSL_VERIFYPEER. A surprising number of small wrappers disable verification to make local dev "work." Grep the source for it before shipping. A deprecation patch is not a security audit — assume nothing changed here.curl_close() happens (or that handles aren't cached indefinitely) — long-running workers will otherwise leak.json_decode yourself so a malformed body doesn't silently become null downstream.curl_getinfo() on failure — http_code vs errno tells you whether the problem is network, TLS, or the remote service. If you upgraded to 1.0.6 purely to silence a deprecation, confirm the notice is actually gone rather than suppressed by your error handler.$this->app->extend() or your own adapter. Don't monkey-patch.How can I help you explore Laravel packages today?