Install the Bundle:
composer require dunglas/digital-ocean-bundle symfony/http-client nyholm/psr7 guzzlehttp/promises
Add to config/bundles.php:
Dunglas\DigitalOceanBundle\DunglasDigitalOceanBundle::class => ['all' => true],
Configure API Token:
In .env:
DIGITAL_OCEAN_TOKEN=your_digital_ocean_api_token
Or in config/packages/dunglas_digital_ocean.yaml:
dunglas_digital_ocean: "%env(DIGITAL_OCEAN_TOKEN)%"
First Use Case:
Inject the Client into a controller or command:
use DigitalOceanV2\Client;
#[Route('/droplets', name: 'list_droplets')]
public function listDroplets(Client $doClient): Response
{
$droplets = $doClient->droplet()->getAll();
return $this->json($droplets);
}
src/Controller/DigitalOceanController.php in the example for a quick start.Dependency Injection:
DigitalOceanV2\Client into any Symfony service (controllers, commands, event subscribers, etc.).# config/packages/dunglas_digital_ocean.yaml
dunglas_digital_ocean:
connections:
production: "%env(DIGITAL_OCEAN_PROD_TOKEN)%"
staging: "%env(DIGITAL_OCEAN_STAGING_TOKEN)%"
default_connection: production
Then inject:
public function __construct(
private Client $productionClient,
private Client $stagingClient
) {}
Pagination Handling:
ResultPager for large datasets:
$pager = new ResultPager($doClient);
$droplets = $pager->fetchAll($doClient->droplet(), 'getAll');
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
#[ApiResource(
normalizationContext: ['groups' => ['droplet:read']],
paginationItemsPerPage: 20
)]
class Droplet {}
Async Operations:
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
#[AsMessageHandler]
public function handle(CreateDropletMessage $message, Client $doClient)
{
$doClient->droplet()->create($message->dropletData);
}
API Platform Integration:
#[ApiResource(
operations: [
new GetCollection(),
new Get(),
new Post(
uriTemplate: '/droplets',
validationContext: ['groups' => ['droplet:create']]
)
]
)]
class Droplet {}
ApiPlatform\Metadata\Operation to customize API methods:
#[ApiResource]
class Droplet
{
#[Get(name: 'get_droplet_actions')]
public function getActions(Client $doClient, string $id): array
{
return $doClient->droplet()->actions()->get($id);
}
}
Command-Line Automation:
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class ScaleDropletsCommand extends Command
{
protected static $defaultName = 'do:scale-droplets';
protected function execute(InputInterface $input, OutputInterface $output, Client $doClient): int
{
$droplets = $doClient->droplet()->getAll();
foreach ($droplets as $droplet) {
if ($droplet->memory < 2) {
$doClient->droplet()->resize($droplet->id, 's-2vcpu-2gb');
}
}
return Command::SUCCESS;
}
}
Provisioning Workflow:
#[Post('/deploy', name: 'deploy_app')]
public function deploy(
Request $request,
Client $doClient,
EntityManagerInterface $em
): Response {
$data = json_decode($request->getContent(), true);
$droplet = $doClient->droplet()->create($data['droplet']);
$em->persist($droplet); // Store in your DB
return $this->json(['droplet_id' => $droplet->id]);
}
Monitoring Workflow:
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class MonitorDropletsCommand extends Command
{
protected static $defaultName = 'do:monitor-droplets';
protected function execute(InputInterface $input, OutputInterface $output, Client $doClient): int
{
$droplets = $doClient->droplet()->getAll();
foreach ($droplets as $droplet) {
if ($droplet->status === 'new') {
$output->writeln("Droplet {$droplet->id} is still provisioning!");
}
}
return Command::SUCCESS;
}
}
Cleanup Workflow:
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class CleanupDropletsCommand extends Command
{
protected static $defaultName = 'do:cleanup-droplets';
protected function execute(InputInterface $input, OutputInterface $output, Client $doClient): int
{
$droplets = $doClient->droplet()->getAll();
foreach ($droplets as $droplet) {
if ($droplet->createdAt < new \DateTime('-30 days')) {
$doClient->droplet()->delete($droplet->id);
$output->writeln("Deleted droplet {$droplet->id}");
}
}
return Command::SUCCESS;
}
}
Testing:
Client in tests using Mockery or PHPUnit:
use DigitalOceanV2\Client;
use DigitalOceanV2\Droplet\Droplet;
$mockClient = Mockery::mock(Client::class);
$mockClient->shouldReceive('droplet')->andReturnSelf();
$mockClient->shouldReceive('getAll')->andReturn([new Droplet(['id' => 1])]);
$this->container->set(Client::class, $mockClient);
Error Handling:
try {
$droplet = $doClient->droplet()->get($id);
} catch (\DigitalOceanV2\Exception\ApiException $e) {
$this->logger->error('Failed to fetch droplet: ' . $e->getMessage());
throw new \RuntimeException('Droplet not found', 404, $e);
}
Caching:
use Symfony\Contracts\Cache\CacheInterface;
public function __construct(
private Client $doClient,
private CacheInterface $cache
) {}
public function getDroplets(): array
{
return $this->cache->get('droplets', function () {
return $this->doClient->droplet()->getAll();
}, 300); // Cache for 5 minutes
}
Webhooks:
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
#[AsMessageHandler]
public function handleWebhook(DigitalOceanWebhookMessage $message, Client $doClient)
{
if ($message->event === 'droplet.create') {
$droplet = $doClient->droplet()->get($message->dropletId);
How can I help you explore Laravel packages today?