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

Digital Ocean Domain Bundle Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

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:

  1. 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.
  2. 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.
  3. README.md and any docs/ — look for the service ID or constructor signature that expects a DigitalOcean API token.
  4. The 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.

Implementation Patterns

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.

Gotchas and Tips

  • Empty changelog. 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.
  • It is a bundle, not a Laravel package. No 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.
  • Two HTTP stacks. Laravel's 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.
  • Token scopes. A DigitalOcean token with read scope will list domains and fail on writes with a 403 that surfaces through the bundle as a generic exception. Verify scope before debugging your own code.
  • Rate limits and 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.
  • Apex records use @. 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.
  • Deleting a domain is irreversible and removes every record beneath it, including MX and verification TXT. Never expose domain deletion through a UI without a typed confirmation; prefer soft-deletes in your own table plus an explicit purge job.
  • Propagation is not instant. TTL and resolver caching mean a freshly written record is not visible for seconds-to-minutes. Do not assert propagation in the same request; poll with a bounded timeout, and remember DO's own nameservers answer before the registry does.
  • Debugging visibility is yours to add. The bundle probably exposes no logger. If its constructor accepts a PSR-3 logger or an HTTP client, inject one with request/response middleware; otherwise wrap every public call in your DomainManager with Log::debug() of method, args, and status.
  • Watch transitive SDK churn. If 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.
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.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo