fopost/symfony-bundle
A Symfony bundle that integrates fopost into Symfony applications, providing bundle configuration, service registration, and dependency injection wiring so you can start using fopost features with minimal setup and standard Symfony conventions.
fopost/fopost-symfony is the Symfony integration layer for the Fopost platform, wrapping fopost/sdk. v0.2.0 is the second tagged release and the first with meaningful feature surface (Meta Ads depth), so treat it as early-stage: pin the version and read the source before relying on it.
Minimal path:
composer require fopost/fopost-symfony:^0.2 — note this transitively pins fopost/sdk to ^0.2 (see Gotchas).config/services.php and env() rather than a Symfony YAML file.Where to look first, in order: the fopost/sdk changelog for 0.2.x, the bundle's DependencyInjection/ directory (to see exactly which services are defined and their IDs), then the PR titled "Feature/meta ads depth" (#4) since that is the only functional change in this release.
Bind the SDK client as a singleton. Do not let the container rebuild an HTTP client per resolution.
// app/Providers/FopostServiceProvider.php
public function register(): void
{
$this->app->singleton(\Fopost\Sdk\Client::class, fn ($app) => new \Fopost\Sdk\Client(
token: config('services.fopost.token'),
baseUri: config('services.fopost.base_uri', 'https://api.fopost.com'),
));
}
Verify the actual constructor signature against vendor/fopost/sdk/src — it is not stable at 0.2.
Wrap, don't scatter. Put every Fopost call behind one application-level service (App\Services\FopostGateway) that returns your own DTOs. The SDK is pre-1.0 and its argument shapes will move; a single adapter file is the difference between a one-line upgrade and a codebase-wide refactor.
Queue anything that writes. Publishing posts and creating ad entities are network-bound and rate-limited. Pattern:
final class PublishPost implements ShouldQueue
{
use InteractsWithQueue, Queueable;
public int $tries = 3;
public function __construct(private PostDraft $draft) {}
public function handle(FopostGateway $fopost): void
{
$result = $fopost->publish($this->draft);
$this->draft->markPublished($result->externalId, $result->permalink);
}
public function backoff(): array { return [10, 60, 300]; }
}
Persist the external ID returned by the API immediately — it is your only handle for later edits, deletes, and insight lookups.
Meta Ads depth (new in v0.2.0). The new surface covers campaign/ad-set/ad hierarchy rather than single-object calls. Model it in your domain as a three-level tree with local rows mirroring remote IDs, and treat the API response as authoritative on refresh. Typical flow: create campaign → create ad set(s) referencing the campaign ID → create ad(s) referencing the ad set ID. Each step is a separate remote call, so a partial failure leaves an orphaned parent; record intent (a pending status plus the parent ID) before each call so a retry job can resume rather than re-create. Keep a nightly reconcile job that pulls remote state and diffs it against your table — you will drift otherwise.
Read-through caching for insights. Ad metrics endpoints are the most expensive calls you'll make. Cache per (entity, date range) with a TTL keyed to how stale the platform's own reporting is, and never cache inside a request that also writes.
Testing. Fake at your gateway boundary, not the SDK, so upgrades don't break your test suite. Add one narrow integration test (opt-in via env var, hitting a sandbox account) that exercises auth + a single read; that catches credential and transport regressions cheaply.
config/fopost.php published for you, no tagged services. You get the package's classes, not its container wiring. If you find yourself fighting DependencyInjection/Extension, stop and register the SDK client manually.fopost/sdk ^0.2 until 0.3 is published — this was an explicit, temporary pin (PR #5). The moment fopost/sdk 0.3 lands, this bundle will not install alongside it, and a composer update in an unrelated package can surface it as an unexpected conflict. Lock your composer.lock, and watch for a corresponding bundle release before bumping the SDK.PlatformAdapter interface with a MetaAdsAdapter implementation keeps the asymmetry honest.ads_management on the connected account surfaces as a generic 4xx. Verify with a manual call before filing anything upstream.How can I help you explore Laravel packages today?