Installation:
composer require bmatschullat/ups-api-bundle
Ensure your config/bundles.php includes:
return [
// ...
Bmatschullat\UpsApiBundle\UpsApiBundle::class => ['all' => true],
];
Configuration:
Add UPS credentials to config/packages/ups_api.yaml:
ups_api:
account_number: 'YOUR_UPS_ACCOUNT_NUMBER'
user_id: 'YOUR_UPS_USER_ID'
password: 'YOUR_UPS_PASSWORD'
sandbox: true # Set to false for production
First Use Case:
Ship a package using the ShipmentService:
use Bmatschullat\UpsApiBundle\Service\ShipmentService;
$shipmentService = $this->get('ups_api.shipment_service');
$shipment = $shipmentService->createShipment([
'shipper' => [
'name' => 'Your Company',
'address' => [
'addressLine' => ['123 Main St'],
'city' => 'New York',
'stateProvinceCode' => 'NY',
'postalCode' => '10001',
'countryCode' => 'US'
]
],
'shipTo' => [
'name' => 'Recipient Name',
'address' => [
'addressLine' => ['456 Oak Ave'],
'city' => 'Los Angeles',
'stateProvinceCode' => 'CA',
'postalCode' => '90001',
'countryCode' => 'US'
]
],
'package' => [
'packagingType' => '02', // Customer Supplied Package
'dimensions' => [
'unitOfMeasurement' => 'IN',
'length' => '10',
'width' => '5',
'height' => '4',
'packageCode' => '01' // Package
],
'packageWeight' => [
'unitOfMeasurement' => 'LBS',
'weight' => '2.0'
]
],
'shipmentServiceOptions' => [
'service' => '01' // Ground
]
]);
Check Documentation: Review the embedded docs for API specifics (e.g., rate shopping, tracking).
Rate Shopping: Compare shipping rates before committing to a shipment:
$rateService = $this->get('ups_api.rate_service');
$rates = $rateService->getRates($shipmentData);
Tracking Shipments: Fetch real-time tracking data:
$trackingService = $this->get('ups_api.tracking_service');
$trackingInfo = $trackingService->getTrackingInfo('1Z999AA10123456784');
Batch Processing: Use dependency injection to inject services into controllers/services:
class OrderController extends AbstractController {
public function __construct(
private ShipmentService $shipmentService,
private RateService $rateService
) {}
}
Event Listeners: Trigger actions post-shipment (e.g., update order status):
# config/services.yaml
services:
App\EventListener\UpsShipmentListener:
tags:
- { name: 'kernel.event_listener', event: 'ups_api.shipment.created', method: 'onShipmentCreated' }
Form Integration: Use Symfony forms to collect shipping data:
$builder->add('shipToAddress', AddressType::class, [
'mapped' => false,
'ups_api' => true // Custom option to validate against UPS rules
]);
Async Processing: Offload heavy API calls (e.g., rate shopping) to a queue (e.g., Symfony Messenger):
$message = new GetUpsRatesMessage($shipmentData);
$this->messageBus->dispatch($message);
Testing:
Mock the UpsApiBundle services in tests:
$this->container->set('ups_api.shipment_service', $this->createMock(ShipmentService::class));
Sandbox vs. Production:
sandbox: true) first. UPS sandbox credentials are documented here.%env%:
password: '%env(UPS_API_PASSWORD)%'
API Rate Limits:
$cache = $this->get('ups_api.cache');
if ($cache->has('rates_' . $cacheKey)) {
return $cache->get('rates_' . $cacheKey);
}
Data Validation:
stateProvinceCode must be 2 chars for US). Use the bundle’s validators or validate manually:
if (!preg_match('/^[A-Z]{2}$/', $stateCode)) {
throw new \InvalidArgumentException('Invalid state code');
}
Deprecation Warnings:
composer.json:
"bmatschullat/ups-api-bundle": "dev-main"
Error Handling:
try {
$response = $shipmentService->createShipment($data);
} catch (\Bmatschullat\UpsApiBundle\Exception\UpsApiException $e) {
$error = simplexml_load_string($e->getResponse());
$this->addFlash('error', (string)$error->Response->Error->Description);
}
Enable API Logging: Configure Monolog to log UPS API requests/responses:
# config/packages/monolog.yaml
handlers:
ups_api:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.ups_api.log"
level: debug
channels: ["ups_api"]
Then enable the channel in your services:
$logger->info('UPS API Request', ['request' => $request, 'response' => $response]);
XML Validation:
Use xmllint to validate UPS API responses:
xmllint --format file.xml --noout
Custom Services: Extend the base services to add domain logic:
class CustomShipmentService extends \Bmatschullat\UpsApiBundle\Service\ShipmentService {
public function createInsuredShipment(array $data, float $insuredValue) {
$data['shipmentServiceOptions']['insuredValue'] = [
'currencyCode' => 'USD',
'monetaryValue' => $insuredValue
];
return parent::createShipment($data);
}
}
Register it in services.yaml:
services:
App\Service\CustomShipmentService:
decorates: 'ups_api.shipment_service'
arguments: ['@App\Service\CustomShipmentService.inner']
Custom Response Mappers: Override how UPS XML responses are mapped to objects:
$this->container->set('ups_api.response_mapper', $this->createMock(UpsResponseMapper::class));
Webhook Integration:
Use Symfony’s HttpClient to poll UPS for shipment updates:
$client = $this->get('http_client');
$response = $client->request('GET', 'https://onlinetools.ups.com/api/track/v1/details', [
'auth_basic' => [$userId, $password],
'query' => ['TrackNum' => $trackingNumber]
]);
Multi-Account Support: Dynamically switch accounts via a parameter:
# config/routes.yaml
ups_shipment:
path: /ship
controller: App\Controller\UpsController::ship
defaults:
account: '%env(UPS_ACCOUNT
How can I help you explore Laravel packages today?