cm2tech/cfm-soap-symfony-bundle
Installation
composer require cm2tech/cfm-soap-symfony-bundle
Ensure your composer.json includes the package under require.
Configuration
Add the bundle to config/bundles.php:
return [
// ...
Cfm\SoapSymfonyBundle\CfmSoapSymfonyBundle::class => ['all' => true],
];
First Use Case: Fetch Doctor Data
Inject the DoctorDataRequest service into a controller or service:
use Cfm\SoapSymfonyBundle\Service\DoctorDataRequest;
use Cfm\SoapSymfonyBundle\Request\DoctorData;
class DoctorController extends AbstractController
{
public function __construct(
private DoctorDataRequest $doctorDataRequest
) {}
public function search(DoctorData $doctorData): JsonResponse
{
$response = $this->doctorDataRequest->Consultar(
$doctorData,
'%env(CFM_API_KEY)%' // Replace with your actual key
);
return $this->json($response);
}
}
Environment Setup
Add your CFM API key to .env:
CFM_API_KEY=your_api_key_here
Request Construction
Use DoctorData DTO to structure input:
$doctorData = new DoctorData('SP', 123456); // UF, CRM
Service Injection Prefer dependency injection over direct instantiation for testability:
// services.yaml
services:
App\Service\DoctorService:
arguments:
$doctorDataRequest: '@cfm_soap_symfony.doctor_data_request'
Response Handling Parse raw SOAP responses into domain objects:
$rawResponse = $doctorDataRequest->Consultar($doctorData, $apiKey);
$doctor = new Doctor(
$rawResponse['nome'],
$rawResponse['especialidades'],
// ...
);
Error Handling Wrap SOAP calls in try-catch blocks:
try {
$response = $doctorDataRequest->Consultar($doctorData, $apiKey);
} catch (\SoapFault $e) {
$this->addFlash('error', 'CFM API Error: ' . $e->getMessage());
return $this->redirectToRoute('home');
}
Caching: Cache frequent SOAP responses (e.g., using Symfony Cache component):
$cache = $this->get('cache.app');
$cacheKey = 'cfm_doctor_' . $doctorData->getCrm();
if (!$cached = $cache->get($cacheKey)) {
$cached = $doctorDataRequest->Consultar($doctorData, $apiKey);
$cache->set($cacheKey, $cached, 3600); // Cache for 1 hour
}
Rate Limiting: Implement a decorator pattern to throttle requests:
class ThrottledDoctorDataRequest implements DoctorDataRequestInterface
{
public function __construct(
private DoctorDataRequest $decorated,
private RateLimiterInterface $limiter
) {}
public function Consultar(DoctorData $data, string $apiKey)
{
$this->limiter->consume('cfm_api');
return $this->decorated->Consultar($data, $apiKey);
}
}
Logging: Log SOAP requests/responses for debugging:
use Psr\Log\LoggerInterface;
$logger->info('CFM SOAP Request', [
'data' => $doctorData->toArray(),
'response' => $response,
]);
SOAP Faults
SOAP-ENV:Client).try-catch and map faults to user-friendly messages:
catch (\SoapFault $e) {
if (strpos($e->getMessage(), 'Invalid CRM') !== false) {
throw new \InvalidArgumentException('CRM not found');
}
}
API Key Exposure
%env() or parameter bags:
# config/packages/cfm_soap.yaml
cfm_soap_symfony:
api_key: '%env(CFM_API_KEY)%'
UTF-8 Encoding
á instead of á).$response = mb_convert_encoding($rawResponse, 'UTF-8', 'ISO-8859-1');
WSDL Caching
$client = new \SoapClient($wsdl, [
'cache_wsdl' => WSDL_CACHE_NONE,
]);
Enable SOAP Traces Configure the SOAP client to log raw requests/responses:
$client = new \SoapClient($wsdl, [
'trace' => 1,
'exceptions' => true,
]);
$request = $client->__getLastRequest();
$response = $client->__getLastResponse();
Validate Input
Use Symfony’s Validator to validate DoctorData:
# config/validator/validation.yaml
Cfm\SoapSymfonyBundle\Request\DoctorData:
constraints:
- All:
- Cfm\SoapSymfonyBundle\Validator\Constraints\ValidUF
- Cfm\SoapSymfonyBundle\Validator\Constraints\ValidCRM
Mock SOAP for Tests
Use php-soap-mock or create a test double:
$this->createMock(\SoapClient::class)
->method('Consultar')
->willReturn(['nome' => 'Test Doctor']);
Custom Requests
Extend the bundle to support additional CFM endpoints (e.g., ConsultarEspecialidades):
class EspecialidadeDataRequest
{
public function ConsultarEspecialidades(string $uf, string $apiKey)
{
$client = new \SoapClient($wsdl);
return $client->ConsultarEspecialidades(['uf' => $uf], ['apiKey' => $apiKey]);
}
}
Event Dispatching Trigger events for SOAP responses:
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
$dispatcher->dispatch(new CfmSoapResponseEvent($response));
Async Processing Offload SOAP calls to a message queue (e.g., Symfony Messenger):
$message = new CfmSoapMessage($doctorData, $apiKey);
$bus->dispatch($message);
Dockerized SOAP For local development, mock the SOAP service with a Docker container:
# Dockerfile
FROM php:cli
RUN pecl install soap
COPY soap_mock.php /usr/local/bin/soap_mock
How can I help you explore Laravel packages today?