dcarbone/php-consul-api-bundle
Install the Bundle
Add to composer.json:
"require": {
"dcarbone/php-consul-api-bundle": "0.6.*"
}
Run composer update.
Register the Bundle
Add to AppKernel.php:
new \DCarbone\PHPConsulAPIBundle\PHPConsulAPIBundle(),
Environment Variables
Set CONSUL_HTTP_ADDR (e.g., http://localhost:8500) to connect to a local Consul agent.
First Use Case Inject the service in a controller/service:
use DCarbone\PHPConsulAPIBundle\Service\ConsulAPIService;
class MyService {
public function __construct(private ConsulAPIService $consul) {}
}
Use it to query Consul:
$services = $this->consul->getCatalog()->getServices();
Service Discovery Fetch registered services dynamically:
$services = $this->consul->getCatalog()->getServices();
// Filter by tags or name
$webServices = array_filter($services, fn($s) => str_contains($s['Service'], 'web'));
Health Checks Register or query health checks:
// Register a check
$this->consul->getAgent()->checkDefine([
'id' => 'service:web',
'name' => 'Web Service Check',
'http' => 'http://localhost:8000/health',
'interval' => '10s',
]);
// Query checks
$checks = $this->consul->getHealth()->getChecks();
Key-Value Store Store/retrieve config dynamically:
$this->consul->getKV()->put('app/config', json_encode(['debug' => true]));
$config = json_decode($this->consul->getKV()->get('app/config')->getValue(), true);
Named Configurations Use multiple Consul agents (e.g., dev/staging/prod):
# config.yml
consul_api:
configurations:
dev:
addr: http://dev-consul:8500
token: dev-token
prod:
addr: http://prod-consul:8500
token: prod-token
Inject the specific service:
$this->consul->setConfiguration('prod');
$services = $this->consul->getCatalog()->getServices();
$this->cache->set('consul_services', $services, 30); // Cache for 30 seconds
symfony/lock to handle Consul API failures gracefully.Deprecated Symfony 3
php-consul/php-consul directly).Configuration Overrides
config.yml under consul_api.configurations. Omitting this will throw errors.default_configuration key points to a valid named config:
consul_api:
default_configuration: dev # Must match a key in `configurations`
configurations:
dev: { addr: http://localhost:8500 }
Token Handling
token_in_header is false (default), the token is passed in the URL. For security, set it to true and configure http_client to handle headers:
consul_api:
configurations:
secure:
token: "your-token"
token_in_header: true
http_client: "http_client_with_auth" # Custom HTTP client
SSL/TLS Issues
insecure_skip_verify: true, disable only in development. For production, provide valid certificates:
consul_api:
configurations:
prod:
ca_file: "%kernel.project_dir%/config/consul-ca.crt"
client_cert: "%kernel.project_dir%/config/client.crt"
client_key: "%kernel.project_dir%/config/client.key"
Rate Limiting
try {
$this->consul->getCatalog()->getServices();
} catch (\GuzzleHttp\Exception\RequestException $e) {
if ($e->getCode() === 429) {
sleep(2); // Retry after 2 seconds
retry();
}
}
Enable Guzzle Logging
Add to config.yml:
consul_api:
configurations:
dev:
http_client:
handler: "http_client_with_logging" # Custom handler with Guzzle middleware
Use the Guzzle\Handler\Log middleware to log requests/responses.
Validate API Responses Always check response statuses:
$response = $this->consul->getKV()->get('nonexistent-key');
if ($response->getStatusCode() !== 200) {
throw new \RuntimeException("Key not found");
}
Environment-Specific Configs
Use %kernel.environment% to load different configs per environment:
# config_%env%.yml
consul_api:
configurations:
dev: { addr: "http://dev-consul:8500" }
prod: { addr: "http://prod-consul:8500" }
Custom HTTP Client Override the default Guzzle client for advanced features (e.g., retry middleware):
consul_api:
configurations:
custom:
http_client: "my_custom_client" # Service ID
Define the service in services.yml:
services:
my_custom_client:
class: GuzzleHttp\Client
calls:
- [setDefaultOption, ['timeout', 30]]
- [setDefaultOption, ['connect_timeout', 5]]
Event Listeners Extend functionality by listening to Consul events (e.g., service registration changes):
// src/EventListener/ConsulListener.php
class ConsulListener {
public function onKernelRequest(GetResponseEvent $event) {
$services = $this->consul->getCatalog()->getServices();
// Trigger logic based on service availability
}
}
Register in services.yml:
services:
consul.listener:
class: App\EventListener\ConsulListener
arguments: ["@consul_api.local"]
tags:
- { name: kernel.event_listener, event: kernel.request }
Decorators
Decorate the ConsulAPIService to add pre/post-processing:
class DecoratedConsulService implements ConsulAPIServiceInterface {
public function __construct(private ConsulAPIService $inner) {}
public function getCatalog() {
// Pre-process (e.g., add caching)
$result = $this->inner->getCatalog();
// Post-process
return $result;
}
}
Register as a decorator in services.yml:
services:
consul_api.local:
decorates: consul_api.local
arguments: ["@consul_api.local.inner"]
How can I help you explore Laravel packages today?