Installation:
composer require driveop/twilio-bundle
config/bundles.php (Symfony 4+) or AppKernel.php (Symfony 3):
DriveOp\TwilioBundle\DriveOpTwilioBundle::class => ['all' => true],
config/packages/driveop_twilio.yaml:
driveop_twilio:
twilio_sid: '%env(TWILIO_SID)%'
twilio_token: '%env(TWILIO_TOKEN)%'
First Use Case:
twilio_client service into a controller or service:
use Symfony\Component\HttpFoundation\Response;
class WhatsAppController extends AbstractController
{
public function sendMessage(Client $twilioClient): Response
{
$to = 'whatsapp:+1234567890'; // Recipient in E.164 format
$from = 'whatsapp:+1987654321'; // Twilio WhatsApp sandbox number
$body = 'Hello from Twilio!';
$message = $twilioClient->sendWhatsAppMessage($to, $from, $body);
return new Response('Message sent: ' . $message->sid);
}
}
Sending Messages:
sendWhatsAppMessage($to, $from, $body) for WhatsApp messages. Validate recipient format (e.g., whatsapp:+1234567890).sendSmsMessage($to, $from, $body) for SMS. Validate from as a Twilio-verified number (e.g., +1234567890).Error Handling:
Twilio\Rest\ApiException):
try {
$message = $twilioClient->sendWhatsAppMessage($to, $from, $body);
} catch (\Twilio\Rest\ApiException $e) {
// Log error or retry logic
$this->logger->error('Twilio error: ' . $e->getMessage());
}
Configuration Management:
%env(TWILIO_SID)%) for sensitive credentials. Avoid hardcoding.config/packages/driveop_twilio.yaml for environment-specific settings.Testing:
Twilio\Rest\Client service in PHPUnit tests:
$this->container->set('twilio_client', $this->createMock(Twilio\Rest\Client::class));
Integration with Symfony Forms:
public function sendMessageAction(Request $request, Client $twilioClient)
{
$form = $this->createForm(WhatsAppForm::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$data = $form->getData();
$twilioClient->sendWhatsAppMessage(
$data['to'],
$data['from'],
$data['body']
);
}
}
WhatsApp Sandbox Limitations:
whatsapp:+14155238886) require approval for production use. Test thoroughly in sandbox before going live.Number Formatting:
whatsapp:+ (e.g., whatsapp:+1234567890).+1234567890) without prefixes.InvalidParameterValue exceptions.Rate Limits:
use Symfony\Component\Stopwatch\Stopwatch;
$stopwatch = new Stopwatch();
$event = $stopwatch->start('twilio_retry');
while (true) {
try {
$message = $twilioClient->sendWhatsAppMessage($to, $from, $body);
break;
} catch (\Twilio\Rest\ApiException $e) {
if ($e->getCode() === 429) {
$event->lap();
sleep($event->getDuration() * 1.5); // Exponential backoff
} else {
throw $e;
}
}
}
Webhook Verification:
use Twilio\Webhooks\Twiml;
public function handleWebhook(Request $request)
{
$twiml = new Twiml();
// Handle incoming messages (e.g., replies)
return new Response($twiml);
}
Dependency Conflicts:
twilio/sdk (^5.0). Ensure no other packages in your project conflict with this version.Logging:
$this->logger->info('Sent WhatsApp message', [
'sid' => $message->sid,
'to' => $to,
]);
Environment-Specific Config:
%kernel.environment% to load different Twilio credentials for dev vs. prod:
# config/packages/driveop_twilio.yaml
driveop_twilio:
twilio_sid: '%env(resolve:TWILIO_SID_%kernel.environment%)%'
twilio_token: '%env(resolve:TWILIO_TOKEN_%kernel.environment%)%'
Extending the Bundle:
TwilioClient service to add custom logic:
# config/services.yaml
services:
App\Service\CustomTwilioClient:
decorates: 'twilio_client'
arguments:
$inner: '@.inner'
// src/Service/CustomTwilioClient.php
class CustomTwilioClient extends TwilioClient
{
public function sendWhatsAppMessage($to, $from, $body)
{
// Add custom logic (e.g., logging, validation)
return parent::sendWhatsAppMessage($to, $from, $body);
}
}
Template Messages:
$client->messages->create(
$to,
['from' => $from, 'body' => $body, 'templateSid' => 'YOUR_TEMPLATE_SID']
);
Security:
ParameterBag to validate credentials on bundle load:
// src/DependencyInjection/DriveOpTwilioExtension.php
if (empty($config['twilio_sid']) || empty($config['twilio_token'])) {
throw new \InvalidArgumentException('Twilio credentials are required.');
}
How can I help you explore Laravel packages today?