brazilianfriendsofsymfony/frete-bundle
Installation
composer require brazilianfriendsofsymfony/frete-bundle
Add to config/bundles.php (Symfony):
return [
// ...
BrazilianFriendsOfSymfony\FreteBundle\BFOSFreteBundle::class => ['all' => true],
];
Configuration
Add to config/packages/bfos_frete.yaml:
bfos_frete:
codigo_empresa: "YOUR_ECT_CODE" # Required (even if empty string)
senha: "INITIAL_PASSWORD" # Required (8-digit CNPJ prefix)
First Use Case Fetch shipping rates for a package:
use BrazilianFriendsOfSymfony\FreteBundle\Service\FreteService;
$freteService = $this->container->get('bfos_frete.service');
$result = $freteService->calcularFrete([
'codigo_servico' => '40010', // SEDEX
'peso' => 1.5,
'altura' => 10,
'largura' => 20,
'comprimento' => 30,
'mao_propria' => 0,
'valor_declarado' => 100.00,
'aviso_recebimento' => 'N',
'cod_ibge_remetente' => '3550308', // São Paulo
'cod_ibge_destino' => '2304408', // Fortaleza
]);
Dynamic Service Selection Use a service locator pattern to fetch rates for multiple carriers (Correios only in this bundle):
$services = ['40010', '41106']; // SEDEX + PAC
$results = $freteService->calcularFreteForServices($services, $packageData);
Caching Responses Cache API responses (e.g., 5-minute TTL) to avoid rate limits:
$cache = $this->container->get('cache.app');
$cacheKey = 'frete_' . md5(serialize($requestData));
$result = $cache->get($cacheKey, function() use ($freteService, $requestData) {
return $freteService->calcularFrete($requestData);
});
Form Integration Validate and submit shipping data in a Symfony form:
// src/Form/ShippingType.php
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
class ShippingType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('service', ChoiceType::class, [
'choices' => [
'SEDEX' => '40010',
'PAC' => '41106',
],
])
->add('weight', NumberType::class);
}
}
Event-Driven Updates Listen for order creation to auto-calculate shipping:
// src/EventListener/ShippingListener.php
use Symfony\Component\HttpKernel\Event\ViewEvent;
class ShippingListener {
public function onKernelView(ViewEvent $event) {
$order = $event->getControllerResult();
if ($order instanceof Order && $order->isShippingCalculated() === false) {
$freteService = $this->container->get('bfos_frete.service');
$order->setShippingCost($freteService->calcularFrete($order->getShippingData()));
}
}
}
Empty Parameters
codigo_empresa and senha must be passed (even as empty strings) or the API will reject the request.if (empty($this->getParameter('bfos_frete.codigo_empresa'))) {
throw new \RuntimeException('Correios ECT code is required in config.');
}
Rate Limits
try {
$result = $freteService->calcularFrete($data);
} catch (RateLimitExceededException $e) {
sleep(60); // Wait 1 minute
retry();
}
IBGE Codes
cod_ibge_remetente/cod_ibge_destino (e.g., 0000000) will return null for all services.Service Code Typos
codigo_servico (e.g., 4001 instead of 40010) returns null.const SERVICES = [
'SEDEX' => '40010',
'PAC' => '41106',
];
Enable API Logging Configure Monolog to log raw API responses:
# config/packages/monolog.yaml
handlers:
frete:
type: stream
path: "%kernel.logs_dir%/frete.log"
level: debug
channels: ["frete"]
Then inject the logger:
$logger = $this->container->get('logger');
$logger->debug('Frete API Response', ['response' => $result]);
Mocking for Tests Use a custom service for testing:
// tests/Service/FreteServiceTest.php
$freteService = $this->createMock(FreteService::class);
$freteService->method('calcularFrete')->willReturn(['valor' => 25.50]);
$this->container->set('bfos_frete.service', $freteService);
Custom Response Parsing Override the default response handler:
// src/Service/CustomFreteService.php
class CustomFreteService extends FreteService {
protected function parseResponse($response) {
// Add custom logic (e.g., currency conversion)
$data = parent::parseResponse($response);
$data['valor_convertido'] = $data['valor'] * 1.2; // Example
return $data;
}
}
Register as a service:
services:
App\Service\CustomFreteService:
decorates: 'bfos_frete.service'
Additional Carriers Extend the bundle to support other APIs (e.g., JADLog, Transportadora X):
// src/Service/MultiCarrierFreteService.php
class MultiCarrierFreteService {
private $correios;
private $jadlog;
public function __construct(FreteService $correios, JadlogService $jadlog) {
$this->correios = $correios;
$this->jadlog = $jadlog;
}
public function calculateAll($data) {
return [
'correios' => $this->correios->calcularFrete($data),
'jadlog' => $this->jadlog->calculate($data),
];
}
}
Webhook Integration Trigger shipping calculations via webhook (e.g., after order creation):
// src/Controller/WebhookController.php
class WebhookController extends AbstractController {
public function calculateShipping(Request $request) {
$data = json_decode($request->getContent(), true);
$freteService = $this->get('bfos_frete.service');
$result = $freteService->calcularFrete($data['package']);
return $this->json($result);
}
}
Route:
# config/routes.yaml
app_calculate_shipping:
path: /api/webhook/shipping
methods: [POST]
controller: App\Controller\WebhookController::calculateShipping
How can I help you explore Laravel packages today?