tourze/digital-ocean-domain-bundle
Symfony bundle for managing DigitalOcean domains and DNS records from your PHP application. Integrates with DigitalOcean’s API to list domains, configure DNS records, and automate domain operations through configurable services.
The release notes for 0.0.2 contain only a Full Changelog link with no described changes — treat the diff as the source of truth before adopting.
composer require tourze/digital-ocean-domain-bundle:0.0.2
Pin the exact version (0.0.2, not ^0.0.2) while you audit the diff. Anything in the 0.0.x line is pre-stable and may rename classes or change method signatures between patches.
Look here first, in this order:
composer.json — check "type". Tourze publishes Symfony bundles; if it is symfony-bundle, Laravel's package discovery will not register it. You are consuming the PHP classes inside it, not the bundle wiring.src/ — identify the entry point: normally a *Bundle class plus a DependencyInjection/ extension, and the actual API client/DTO/service classes sitting alongside. The client and DTOs are what you can use from Laravel.README.md and any docs/ — look for the service ID or constructor signature that expects a DigitalOcean API token.0.0.1...0.0.2 compare view — note renamed classes, changed constructor arguments, or bumped transitive SDK versions.First use case: list the domains on your DigitalOcean account and read the DNS records for one of them. That is a read-only call, it validates your token and scopes, and it tells you the shape of the returned objects before you touch writes.
$domains = $client->getDomains(); // inspect actual return type
$records = $client->getDomainRecords('example.com');
Confirm the real method names against src/ — do not code against the names above until you have.
Bridge the client into the container yourself. Since Laravel will not boot the Symfony DI extension, register the underlying client as a singleton in a ServiceProvider and feed it the token from config:
// config/services.php
'digital_ocean' => ['token' => env('DIGITALOCEAN_TOKEN')],
// AppServiceProvider::register()
$this->app->singleton(DomainClient::class, fn () => new DomainClient(
config('services.digital_ocean.token')
));
Wrap it behind your own interface (DomainManager) so the bundle's pre-1.0 class names never leak into controllers or jobs. When 0.0.3 renames something, you change one binding.
Model DNS writes as upserts. The DigitalOcean API has no upsert endpoint, so the pattern is: fetch records for the domain → find by type + name → update if present, create if not → assert the resulting state. Build this once as ensureRecord(string $domain, array $record) and reuse it for every provisioning path. Without it you will accumulate duplicate A/TXT records, which break _acme-challenge verification and mail authentication.
Drive provisioning from queued jobs. Domain creation and record changes are slow, rate-limited, and occasionally flaky. A job with $tries = 3, backoff() returning [10, 60, 300], and rateLimiter middleware containing the blast radius. Keep the HTTP call idempotent (upsert, not blind create) so a retry after a timeout does not double-write.
Treat the client as a boundary and map out. The bundle returns its own DTOs. Convert to your Eloquent models or plain arrays at the edge — $record->getName() may become $record->name, fields may be nullable, IDs may be strings. Mapping in one place makes tests and future upgrades cheap.
Cache reads aggressively, invalidate on write. Domain lists and record sets change rarely and cost an API call each time. Cache::remember("do:dns:{$domain}", 300, ...) and forget the key inside the same service method that performs a write. Do not cache through the bundle itself; it has no knowledge of your cache.
Test with the HTTP layer, not the bundle. The bundle likely uses PSR-18/PSR-17 discovery. Under Laravel that may resolve to Guzzle directly rather than Laravel's Http facade, so Http::fake() may not intercept it. Pass a fake PSR-18 client into the constructor if the signature allows; otherwise assert against a scripted MockHandler on the Guzzle instance the bundle actually instantiates.
Extension point: decorate, do not fork. Compose the bundle's client inside your DomainManager and add retries, logging, and idempotency there. Forking a 0.0.x package means re-applying your patch on every release.
0.0.2 ships a compare link and nothing else. Run composer diff / read the compare view for renamed symbols and dependency bumps before upgrading from 0.0.1. Assume semantic versioning does not apply yet.extra.laravel.providers, no facades, no config/*.php publish tag. Expect Symfony Reference-style wiring in the extension that you cannot use. Budget an hour to cherry-pick the useful classes.Http facade and the bundle's PSR-18 client are different objects. Faking the wrong one produces tests that pass green while production calls the real API. Log the resolved client class once in a tinker session.403 that surfaces through the bundle as a generic exception. Verify scope before debugging your own code.429. DigitalOcean throttles per-token. A 429 inside a queued job without backoff looks like a hard failure and burns your retry budget in seconds.@. A record created for example.com should have name @, not the FQDN. Subdomains take the relative label (www), not www.example.com. This is the most common silent misconfiguration.DomainManager with Log::debug() of method, args, and status.0.0.2 bumped an underlying SDK, response DTOs may have gained or lost nullable properties. Add a narrow contract test that hits a fake response for getDomains and getDomainRecords so a patch bump breaks CI rather than production.How can I help you explore Laravel packages today?