shippable / hub
Shipping Service Package for Laravel with Strategy and Adapter patterns
v1.0.4
2026-06-22 02:53 UTC
Requires
- php: ^8.2
- illuminate/console: ^9.0|^10.0|^11.0
- illuminate/database: ^9.0|^10.0|^11.0
- illuminate/http: ^9.0|^10.0|^11.0
- illuminate/support: ^9.0|^10.0|^11.0
README
Laravel Package cung cấp dịch vụ vận chuyển qua Strategy + Adapter Pattern, hỗ trợ GHN, GHTK và ViettelPost.
Cài đặt
1. Thêm local path (development)
// composer.json của dự án { "repositories": [ { "type": "path", "url": "../package-php/shipping", "options": { "symlink": true } } ], "require": { "wf/shipping": "*" } }
composer require wf/shipping --ignore-platform-reqs
2. Publish config (tuỳ chọn)
php artisan vendor:publish --tag=shipping-config
Package sẽ tự động load config mặc định nếu bạn chưa publish. Chỉ publish khi muốn tuỳ chỉnh.
3. Thêm biến môi trường vào .env
# GHN GHN_TOKEN=your-ghn-token GHN_BASE_URL=https://dev-online-gateway.ghn.vn/shiip/public-api # GHTK GHTK_TOKEN=your-ghtk-token GHTK_B2C_TOKEN=your-ghtk-b2c-token GHTK_ENDPOINT=https://services.giaohangtietkiem.vn # ViettelPost VIETTELPOST_TOKEN=your-vtp-token VIETTELPOST_ENDPOINT=https://partner.viettelpost.vn
Cách sử dụng
Package sử dụng Factory Pattern để bạn có thể tuỳ ý gọi dịch vụ ở bất cứ đâu (Controller, Job, Command) mà không bị phụ thuộc vào HTTP Request.
Cách 1 — Inject qua Constructor (Recommended)
use Wf\Shipping\ShippingFactory; use Wf\Shipping\DTO\StandardShippingPayload; class OrderController extends Controller { public function __construct( private readonly ShippingFactory $shippingFactory ) {} public function createOrder(Request $request) { $payload = StandardShippingPayload::fromArray($request->validated()); // Bạn có thể chọn hãng vận chuyển động từ request hoặc fix cứng $method = $request->input('service_method', 'express'); // express, standard, fast $strategy = $this->shippingFactory->make($method); $result = $strategy->createOrder($payload); return response()->json($result); } }
Cách 2 — Resolve thủ công qua app()
use Wf\Shipping\ShippingFactory; $factory = app(ShippingFactory::class); $ghnStrategy = $factory->make('express'); $ghtkStrategy = $factory->make('standard');
Cách 3 — Dùng trực tiếp SDK thô
use Wf\Shipping\GHN; use Wf\Shipping\GHTK; use Wf\Shipping\ViettelPost; $ghn = new GHN(config('shipping.ghn.token')); $resp = $ghn->getProvince(); // array $ghtk = new GHTK(config('shipping.ghtk.token')); $fee = $ghtk->caculateFee([...]); // json string $vtp = new ViettelPost(config('shipping.viettelpost.token')); $provinces = $vtp->getProvice(); // json string
Cấu trúc package
src/
├── config/
│ └── shipping.php ← Cấu hình endpoint, token, service_method
├── Contracts/
│ └── ShippingStrategyInterface.php ← Interface chính dự án inject
├── DTO/
│ └── StandardShippingPayload.php ← DTO chuẩn hoá payload đầu vào
├── Adapters/
│ ├── GHNAdapter.php ← Map DTO → format GHN
│ ├── GHTKAdapter.php ← Map DTO → format GHTK
│ └── ViettelPostAdapter.php← Map DTO → format VTP
├── Strategies/
│ ├── GHNStrategy.php ← Xử lý logic GHN, gọi GHN SDK
│ ├── GHTKStrategy.php ← Xử lý logic GHTK, gọi GHTK SDK
│ └── ViettelPostStrategy.php
├── GHN.php ← SDK gọi GHN API thật
├── GHTK.php ← SDK gọi GHTK API thật
├── ViettelPost.php ← SDK gọi ViettelPost API thật
└── Providers/
└── ShippingServiceProvider.php
Thêm hãng vận chuyển mới
- Tạo
src/Adapters/NewCarrierAdapter.php— map DTO sang format của hãng. - Tạo
src/Strategies/NewCarrierStrategy.php— gọi SDK qua Adapter. - Thêm vào
ShippingServiceProvider::register():new NewCarrierStrategy(token: config('shipping.newcarrier.token')),
- Thêm config vào
src/config/shipping.php.
Interface cần implement
interface ShippingStrategyInterface { public function getServiceMethodName(): string; public function createOrder(StandardShippingPayload $payload): array; public function calculateFee(StandardShippingPayload $payload): array; public function cancelOrder(string $orderCode): array; public function getOrderDetail(string $orderCode): array; public function getProvince(): array; public function getDistrict(int $provinceId): array; public function getWard(int|string $districtId): array; }