omobude / dhl-symfony-bundle
Modern Symfony 7+ bundle for DHL API integration. Create shipment labels and download DHL shipment labels with ease.
Installs: 4
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
Type:symfony-bundle
pkg:composer/omobude/dhl-symfony-bundle
Requires
- php: ^8.2
- psr/log: ^3.0
- symfony/cache: ^7.0
- symfony/config: ^7.0
- symfony/dependency-injection: ^7.0
- symfony/framework-bundle: ^7.0
- symfony/http-client: ^7.0
Requires (Dev)
- phpunit/phpunit: ^10.0
- symfony/phpunit-bridge: ^7.0
This package is auto-updated.
Last update: 2026-02-07 01:59:33 UTC
README
Modern Symfony 7+ bundle for DHL API integration. Create shipment labels, view and download DHL shipments label with ease using OAuth authentication.
Features
- ๐ Create DHL shipments
- ๐ฆ Download shipping labels (PDF)
- ๐ OAuth 2.0 authentication with automatic token management
- โก Token caching for optimal performance
- ๐งช Sandbox mode for testing
- ๐ Comprehensive logging support
- ๐ฏ Type-safe models with PHP 8.2+
- ๐ Modern Symfony 7 integration
Requirements
- PHP 8.2 or higher
- Symfony 7.0 or higher
- Symfony Cache component
- DHL Developer Account (Sign up here)
Table of Contents
- Installation
- Getting DHL Credentials
- Usage
- Configuration Reference
- Switching to Production
- Troubleshooting
- Contributing
- License
Installation
Step 1: Install the Bundle
composer require omobude/dhl-symfony-bundle
Step 2: Configure Environment Variables
Add your DHL credentials to your .env file:
###> omobude/dhl-symfony-bundle ### DHL_CLIENT_ID=your_dhl_client_id_here DHL_CLIENT_SECRET=your_dhl_client_secret_here DHL_CLIENT_SANDBOX=true ###< omobude/dhl-symfony-bundle ###
Step 3: Create Bundle Configuration
Create the file config/packages/omobude_dhl.yaml:
omobude_dhl: client_id: '%env(DHL_CLIENT_ID)%' client_secret: '%env(DHL_CLIENT_SECRET)%' sandbox: '%env(bool:DHL_CLIENT_SANDBOX)%'
Step 4: Clear Cache
php bin/console cache:clear
Getting DHL Credentials
For Sandbox (Testing)
- Go to DHL Developer Portal
- Sign up for a free account
- Create a new application
- Navigate to your application settings
- Copy your Client ID and Client Secret
- Use these credentials in your
.envfile
For Production
- Contact DHL to request production API access
- Complete any required business verification
- Receive your production Client ID and Client Secret
- Update your production environment variables
- Set
sandbox: falsein your configuration
Usage
Creating a Shipment
<?php declare(strict_types=1); namespace App\Controller; use Omobude\DhlBundle\Exception\DhlApiException; use Omobude\DhlBundle\Exception\DhlAuthenticationException; use Omobude\DhlBundle\Exception\DhlDownloadLabelException; use Omobude\DhlBundle\Model\ConsigneeAddress; use Omobude\DhlBundle\Model\PickupData; use Omobude\DhlBundle\Model\SenderAddress; use Omobude\DhlBundle\Model\ShipmentData; use Omobude\DhlBundle\Model\ShipmentDetails; use Omobude\DhlBundle\Service\DhlApiClient; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\BinaryFileResponse; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; class ShippingController extends AbstractController { #[Route('/create-shipment', name: 'create_shipment')] public function createShipment(DhlApiClient $dhlClient): Response { try { $pickupData = new PickupData( date: new \DateTimeImmutable('now', new \DateTimeZone("Europe/London")), accountAddress: true ); $senderAddress = new SenderAddress( companyName: 'XXXXXXXXXX LIMITED', address1: 'UNIT 5C, XXXXXXX DRIVE', city: 'SHEFFIELD', postalCode: 'XXXXX', country: 'GB', name: 'DISPATCH MANAGER', phone: '07443822832', email: 'customersupport@xxxxxxxxxx.com', address2: 'XXXXXXXXXX HOUSE', address3: 'SHEFFIELD' ); $consigneeAddress = new ConsigneeAddress( name: 'JOHN DOE', address1: '123 CUSTOMER STREET', city: 'LONDON', postalCode: 'XXXXXX', country: 'GB', phone: '07123456789', email: 'customer@example.com', recipientType: 'residential', addressType: 'doorstep', address2: 'APARTMENT 4B' ); $shipmentDetails = new ShipmentDetails( customerRef1: 'TN-' . date('YmdHis'), customerRef2: substr(md5(uniqid()), 0, 8), orderedProduct: '1', // 1 = Next day, 48 = 48 hours totalPieces: 1, totalWeight: 5.5 ); $shipmentData = new ShipmentData( pickupAccount: 'XXXXXXX', dropoffType: 'PICKUP', consigneeAddress: $consigneeAddress, pickupData: $pickupData, senderAddress: $senderAddress, shipmentDetails: $shipmentDetails, ); // Create shipment with PDF label $result = $dhlClient->createShipment($shipmentData); return $this->json([ 'success' => true, 'shipment_id' => $result->getShipmentId(), 'message' => 'Shipment created successfully', ]); } catch (DhlApiException|DhlAuthenticationException $ex) { return $this->json([ 'success' => false, 'error' => $ex->getMessage(), 'code' => $ex->getCode(), ], $ex->getCode()); } } }
Downloading a Label
/** * Download shipping label as a file (PDF). * Returns a BinaryFileResponse that automatically downloads the file. */ #[Route('/label/{shipmentId}', name: 'get_label')] public function getLabel(string $shipmentId, DhlApiClient $dhlClient): Response { try { return $dhlClient->getLabel($shipmentId); } catch (DhlAuthenticationException $ex) { return $this->json([ 'success' => false, 'error' => 'Authentication failed', 'message' => $ex->getMessage(), ], Response::HTTP_UNAUTHORIZED); } catch (DhlDownloadLabelException $ex) { return $this->json([ 'success' => false, 'error' => 'Failed to process label', 'message' => $ex->getMessage(), ], Response::HTTP_INTERNAL_SERVER_ERROR); } catch (DhlApiException $ex) { return $this->json([ 'success' => false, 'error' => 'DHL API error', 'message' => $ex->getMessage(), ], $ex->getCode() ?: Response::HTTP_BAD_REQUEST); } }
/** * Inline display of label (opens in browser). */ #[Route('/label/{shipmentId}/view', name: 'view_label', methods: ['GET'])] public function viewLabel(string $shipmentId, DhlApiClient $dhlClient): BinaryFileResponse|Response { try { $response = $dhlClient->getLabel($shipmentId); // Change disposition to inline so it opens in browser $response->headers->set( 'Content-Disposition', sprintf('inline; filename="label-%s.pdf"', $shipmentId) ); return $response; } catch (DhlAuthenticationException | DhlDownloadLabelException | DhlApiException $e) { return $this->json([ 'success' => false, 'error' => $e->getMessage(), ], $e->getCode() ?: Response::HTTP_BAD_REQUEST); } }
Checking Sandbox Mode
if ($dhlClient->isSandbox()) { // Running in sandbox mode echo "Testing mode - no real shipments created"; } else { // Running in production mode echo "Production mode - real shipments will be created"; }
Configuration Reference
| Option | Type | Required | Default | Description |
|---|---|---|---|---|
client_id |
string | Yes | - | Your DHL OAuth Client ID |
client_secret |
string | Yes | - | Your DHL OAuth Client Secret |
sandbox |
boolean | Yes | Enable sandbox/testing mode |
DHL Product Codes
Common product codes for orderedProduct:
| Code | Service | Delivery Time |
|---|---|---|
1 |
DHL Parcel | Next day |
48 |
DHL Parcel Neighbour | 48 hours |
Recipient Types
Valid values for recipientType:
residential- Home deliverybusiness- Business address
Address Types
Valid values for addressType:
doorstep- Standard deliveryneighbour- Deliver to neighbour if recipient not available
Switching to Production
Step 1: Update Environment Variables
Update your production .env file:
###> omobude/dhl-symfony-bundle ### DHL_CLIENT_ID=your_production_client_id DHL_CLIENT_SECRET=your_production_client_secret DHL_CLIENT_SANDBOX=false ###< omobude/dhl-symfony-bundle ###
Step 3: Clear Production Cache
php bin/console cache:clear --env=prod
Step 4: Test in Production
Always test with a single shipment first to ensure everything works correctly.
Troubleshooting
Authentication Errors
Problem: "Authentication failed" or "Invalid credentials"
Solution:
- Verify your Client ID and Client Secret are correct
- Ensure you're using sandbox credentials with
sandbox: true - Check that credentials are properly set in
.env - Try clearing the token cache:
php bin/console cache:clear
Configuration Errors
Problem: "The child config 'client_id' under 'omobude_dhl' must be configured"
Solution:
- Ensure
config/packages/omobude_dhl.yamlexists - Verify the configuration syntax is correct
- Check that environment variables are defined in
.env - Run
php bin/console debug:config omobude_dhlto verify
Token Caching Issues
Problem: "Cached token expired" or authentication errors after some time
Solution:
- The bundle automatically refreshes tokens
- Clear cache if issues persist:
php bin/console cache:clear - Check cache directory permissions:
var/cache/should be writable - Verify
symfony/cacheis installed
API Errors
Problem: DHL API returns error codes
Solution:
- Check DHL API Documentation for error codes
- Enable logging to see detailed error messages
- Verify all required fields are provided
- Ensure addresses are in the correct format
Debugging
Enable detailed logging:
# config/packages/monolog.yaml monolog: channels: ['dhl'] handlers: dhl: type: stream path: '%kernel.logs_dir%/dhl.log' level: debug channels: ['dhl']
Check logs:
tail -f var/log/dhl.log
Verify bundle configuration:
php bin/console debug:config omobude_dhl php bin/console debug:container DhlApiClient
Environment-Specific Configuration
Development
# .env.local DHL_CLIENT_ID=sandbox_dev_client_id DHL_CLIENT_SECRET=sandbox_dev_client_secret DHL_CLIENT_SANDBOX=true
Staging
# .env.staging DHL_CLIENT_ID=sandbox_staging_client_id DHL_CLIENT_SECRET=sandbox_staging_client_secret DHL_CLIENT_SANDBOX=true
Production
# .env.production DHL_CLIENT_ID=production_client_id DHL_CLIENT_SECRET=production_client_secret DHL_CLIENT_SANDBOX=false
Security Best Practices
- Never commit credentials - Add
.envto.gitignore - Use environment variables - Store credentials in environment, not code
- Separate environments - Use different credentials for dev/staging/prod
- Monitor access logs - Check DHL dashboard for unusual activity
- Use HTTPS only - The bundle uses HTTPS by default
- Limit permissions - Only grant necessary access to DHL accounts
Recommended .gitignore
.env .env.local .env.*.local .env.production .env.prod
Contributing
Contributions are welcome! Please follow these steps:
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Make your changes
- Write tests for your changes
- Ensure all tests pass:
./vendor/bin/phpunit - Commit your changes:
git commit -m 'Add amazing feature' - Push to the branch:
git push origin feature/amazing-feature - Open a Pull Request
Coding Standards
- Follow PSR-12 coding standards
- Use PHP 8.2+ features (typed properties, readonly, etc.)
- Write PHPDoc comments for all public methods
- Add tests for new features
License
This bundle is released under the MIT License. See the LICENSE file for details.
Author
Omobude Kelly
- GitHub: @komobude2021
- Email: k.omobude2019@gmail.com
Support
Need help? Here are your options:
- ๐ Read the Documentation
- ๐ Report Issues
- ๐ฌ GitHub Discussions
- ๐ง Email Support
- ๐ DHL API Documentation
Acknowledgments
- Built for the Symfony community
- Powered by DHL API
- Inspired by modern Symfony best practices
Made with โค๏ธ for the Symfony community
If this bundle helped you, please consider giving it a โญ on GitHub!