Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Cloud Flare Bundle Laravel Package

happyr/cloud-flare-bundle

Symfony bundle for integrating Cloudflare into your application. It provides configuration and services for the Cloudflare API, helping you manage zones and purge cached content so your Symfony app can automate cache invalidation and keep content fresh through a simple, configurable service layer.

View on GitHub
Deep Wiki
Context7

Getting Started

First, reset expectations. happyr/cloud-flare-bundle is a Symfony bundle, not a Laravel package. composer require will install the source, but there is no service provider, facade, or config-publish hook — the Symfony Bundle class, DI extension, and YAML service definitions will simply never execute. In a Laravel app you get an inert folder of PHP classes. Treat the repo as a reference implementation for the CloudFlare purge contract, not a runtime dependency.

Where to look first, in order:

  1. The bundle's Configuration class (or the README's YAML block) — this is the minimum viable parameter set you'll mirror in a Laravel config file: zone ID, API credentials, HTTP client, timeout.
  2. The service class that actually calls CloudFlare — this is the ~100 lines worth porting. Look for the purge_cache call and whether it sends files: [...] or purge_everything: true.
  3. The event/listener wiring — read it to understand where the bundle expects purges to be triggered, but do not port it; you'll wire Laravel events instead.

Prerequisites before you touch code:

  • A scoped CloudFlare API token with Zone.Cache Purge permission only (not the legacy global key + email pair — the bundle is old enough it may assume the latter, so verify).
  • Your zone ID (from the CloudFlare dashboard overview page).
  • CLOUDFLARE_TOKEN and CLOUDFLARE_ZONE_ID in .env, never in config/.

First use case — the one to build first: purge a single URL when a CMS entry is published.

// app/Services/Cloudflare/CloudflarePurger.php
final class CloudflarePurger
{
    public function __construct(
        private readonly string $zoneId,
        private readonly string $token,
    ) {}

    public function purge(array $urls): void
    {
        Http::withToken($this->token)
            ->timeout(5)
            ->post("https://api.cloudflare.com/client/v4/zones/{$this->zoneId}/purge_cache", [
                'files' => array_values($urls),
            ])
            ->throw();
    }
}

That is the entire useful surface of the bundle, re-expressed natively. Everything else you'll add (queue, retry, dedupe, telemetry) is Laravel-native and was never in the package anyway.

Implementation Patterns

The "read, extract, rebuild" pattern. Don't vendor the bundle. Read it once, extract two artifacts, discard the rest:

  • The config key vocabulary — mirror names where sane (zone, api_key) so anyone who has seen the bundle recognizes your config.
  • The purge HTTP semantics — batch size, response handling, error codes.

Then write a CloudflareCachePurger interface in your domain layer with one method (purge(array $urls, ?string $zone): void), and bind it in a service provider. This gives you a single seam to swap CDNs later — the bundle gives you no such seam because its integration is baked into Symfony plumbing.

Event-driven, not controller-driven. Never call the purger from a controller. Listen on the domain event:

// App\Listeners\PurgeCloudflareCache
public function handle(ContentPublished $event): void
{
    PurgeUrlOnCloudflare::dispatch($event->urls)
        ->onQueue('cdn');
}

This keeps the purge coupling at exactly one place — the listener — regardless of whether publish comes from a controller, an artisan command, an import job, or a scheduled task.

Always queue. Never block publish on CloudFlare. The bundle's fire-and-forget call is tempting to copy synchronously, but a 5-second CloudFlare timeout should never turn into a failed editor save. Dispatch a job with ->onQueue('cdn') and keep the user path fast:

final class PurgeUrlOnCloudflare implements ShouldQueue
{
    use InteractsWithQueue, Queueable;

    public int $tries = 5;
    public array $backoff = [10, 30, 60, 120]; // respect 429s
    public int $timeout = 10;

    public function __construct(public array $urls, public ?string $zone = null) {}

    public function handle(CloudflarePurger $purger): void
    {
        $purger->purge(array_unique($this->urls));
    }

    public function failed(Throwable $e): void
    {
        Log::channel('cloudflare')->error('purge_failed', [
            'urls' => $this->urls, 'zone' => $this->zone, 'error' => $e->getMessage(),
        ]);
    }
}

Dedupe and coalesce before dispatch. A bulk content import can emit thousands of individual purges and blow through CloudFlare's per-zone rate limit. Buffer URLs for a short window and flush in one call:

// Use cache lock or a short-window buffer; flush every ~2s or at 30 URLs

Multi-tenant zone routing. If you serve multiple customers/domains, derive the zone ID from the tenant record — $tenant->cloudflare_zone_id — never by looking up a string in config. This is the highest-severity footgun in the whole integration: a wrong zone ID purges another customer's cache.

Prefer per-URL purges over purge-all. purge_everything: true is a blunt instrument that tanks cache hit ratio and origin load. Use it only for deploy-time "invalidate everything" flows, never for content edits.

Feature-flag the rollout. CLOUDFLARE_PURGE_ENABLED=true in config; enable on one low-traffic zone first, watch the cache-hit-ratio dashboard, then widen.

Keep a manual runbook. A one-line php artisan cloudflare:purge {url} artisan command is your escape hatch when the queue backs up or the token rotates wrong.

Gotchas and Tips

  • No Symfony plumbing will fire. Do not expect autoloading of the bundle's services, no services.yaml merge, no compiler pass, no event subscribers. You will get fatal errors or silent no-ops if you try to resolve its services from Laravel's container. If you truly want to reuse a specific class, extract it into your app/ tree as plain PHP — verify it has no Symfony\Component\… imports first.

  • Check the auth model. Versions of this bundle predating the modern API likely expect global API key + email. Modern CloudFlare mandates scoped API tokens. If you find the email param in the config schema, do not port it — rewrite against the token model. This is security-relevant, not cosmetic.

  • Silent purge failure is the default failure mode. A 200 response with the wrong URLs, or a dropped job, produces no visible error — you just serve stale content. Mitigate with: (a) post-purge verification sampling, (b) alerting on cache-hit-ratio drops, (c) explicit failure logging as in the failed() hook above.

  • 429s are inevitable. CloudFlare rate-limits per-zone purge calls. Retry with exponential backoff, and batch URLs into a single call rather than looping. If you're hitting limits routinely, you've probably got a dedupe bug upstream.

  • Never let timeout become a failed publish. Set an aggressive ->timeout(5) on the HTTP call and catch ConnectionException / RequestException in the job. The user-facing save must succeed regardless.

  • Zone ID blast radius. A staging config pointing at a production zone ID will purge production cache. Store zone IDs in the tenant/team record, and log the zone on every purge for auditability.

  • Token rotation needs a health check. Add a startup check (or a scheduled artisan command) that performs a lightweight CloudFlare API call and alerts on 401/403. Token revocation during rotation is otherwise discovered only via stale content complaints.

  • Config quirks of the bundle itself (if you're reading it): it may hard-code a Guzzle version pin or an upstream client generation. Note this and pin your own dependencies against the current official cloudflare/sdk (or plain Http:: calls, which is often simpler) — do not inherit the bundle's version drift.

  • Extension points you want that the bundle doesn't provide: queued dispatch, retry policies, per-tenant zone resolution, cache-tag purging (Enterprise-only), batching to respect rate limits, metrics/logging. These are yours to build whether you fork or rewrite — which is precisely why a rewrite into ~200 lines of Laravel-native code is cheaper than adopting a frozen dependency.

  • Record the decision. Add a short ADR noting that you evaluated happyr/cloud-flare-bundle and chose to reimplement, with the Symfony-only and abandonment rationale. Otherwise a future engineer will propose it again in six months.

  • Scope the token tightly. A token with Zone:Edit granted "just in case" in the purge path is a supply-chain liability. Request Zone.Cache Purge only, and bind it to specific zones.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console