shimango/gophr 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

shimango/gophr

Composer 安装命令:

composer require shimango/gophr

包简介

A PHP client for the Gophr Courier Service commercial API

README 文档

README

A comprehensive PHP client for the Gophr Courier Service API, enabling seamless integration of courier services into your PHP applications.

Build Status Latest Stable Version Total Downloads License PHP Version Require

Table of Contents

Requirements

Installation

Using Composer (Recommended)

composer require shimango/gophr

Manual Installation

  1. Download this package from GitHub
  2. Run composer install in the package directory
  3. Require the autoloader in your project:
require_once 'vendor/autoload.php';

Quick Start

Here's a simple example to get you started:

<?php
require_once 'vendor/autoload.php';

use Shimango\Gophr\Client;
use Shimango\Gophr\Common\Configuration;

// Initialize the client
$config = new Configuration('YOUR_API_KEY');
$gophr = new Client($config);

// List all jobs
$response = $gophr->listJobs();
$jobs = $response->getContentsArray();

foreach ($jobs['data'] as $job) {
    echo "Job ID: {$job['id']} - Status: {$job['status']}\n";
}

Configuration

The Configuration class manages all settings for API communication.

Constructor Parameters

$config = new Configuration(
    $apiKey,           // Required: Your Gophr API key
    $isSandbox,        // Optional: Use sandbox environment (default: false)
    $apiVersion,       // Optional: API version (default: "v2")
    $proxyPort,        // Optional: Proxy port if needed (default: null)
    $proxyVerifySSL    // Optional: Verify SSL for proxy (default: false)
);

Configuration Examples

Production Environment:

$config = new Configuration('live_api_key_here');

Sandbox/Testing Environment:

$config = new Configuration('test_api_key_here', true);

Using a Proxy:

$config = new Configuration(
    'your_api_key',
    false,              // Production
    'v2',
    8080,              // Proxy port
    true               // Verify SSL
);

Core Concepts

Jobs

A Job represents a complete courier assignment that may include multiple deliveries. All deliveries within a job are completed by the same courier in a single trip.

Deliveries

A Delivery consists of:

  • One pickup location
  • One dropoff location
  • Associated parcels to be transported

Parcels

Parcels are the individual packages within a delivery. A delivery can contain multiple parcels.

Workflow

  1. Create a Job with a pickup, deliveries, and parcels. This can be done in two ways:
    • All at once: Create and confirm the Job in one go.
    • As a draft: Create the Job as a draft and edit it (e.g., add/remove/edit deliveries and parcels) until it is ready to be confirmed.
  2. Confirm the Job to dispatch the courier.

Note: Once a job is confirmed, deliveries and parcels cannot be modified.

Usage Examples

Working with Jobs

Creating a Job

use Shimango\Gophr\Client;
use Shimango\Gophr\Common\Configuration;

$config = new Configuration('YOUR_API_KEY', true); // Sandbox mode
$gophr = new Client($config);

$jobData = [
    'external_id' => '2112',
    'is_confirmed' => 1,
    'pickups' => [
        [
            'earliest_pickup_time' => '2026-08-12T06:17:00+00:00',
            'pickup_deadline' => '2026-08-12T07:13:00+00:00',
            'pickup_address1' => '221B Baker Street',
            'pickup_city' => 'London',
            'pickup_postcode' => 'NW1 6TS',
            'pickup_country_code' => 'GB',
            'pickup_company_name' => 'Elementary Investigations',
            'pickup_person_name' => 'Sherlock Holmes',
            'pickup_email' => 'itiselementary@test.com',
            'pickup_mobile_number' => '07700000000',
            'parcels' => [
                [
                    'parcel_external_id' => '001',
                    'parcel_reference_number' => '0fc35278-60a1-4fb3-9791-4f45c492e120',
                    'parcel_description' => 'Sunglasses',
                    'width' => 10,
                    'length' => 15,
                    'height' => 5,
                    'weight' => 0.5,
                ],
                [
                    'parcel_external_id' => '002',
                    'parcel_reference_number' => '0fc35278-60a1-4fb3-9791-4f45c492e120',
                    'parcel_description' => 'Folding chair',
                    'width' => 50,
                    'length' => 80,
                    'height' => 5,
                    'weight' => 1.5,
                ],
            ],
        ],
    ],
    'dropoffs' => [
        [
            'dropoff_company_name' => 'The Prime Minister\'s Office',
            'dropoff_address1' => '10 Downing Street',
            'dropoff_city' => 'London',
            'dropoff_postcode' => 'SW1A 0AA',
            'dropoff_country_code' => 'GB',
            'dropoff_person_name' => 'The prime minister',
            'dropoff_email' => 'pm@test.com',
            'dropoff_mobile_number' => '07588000000',
            'dropoff_deadline' => '2026-08-12T08:00:00+00:00',
            'parcels' => [
                [
                    'parcel_external_id' => '001',
                ],
                [
                    'parcel_external_id' => '002',
                ],
            ],
        ],
    ],
];

$response = $gophr->createJob($jobData);
$job = $response->getContentsObject();

echo "Created Job ID: {$job->id}\n";

Retrieving a Job

$jobId = 'job_abc123';
$response = $gophr->getJob($jobId);
$job = $response->getContentsArray();

print_r($job);

Updating a Job (Confirming)

$jobId = 'job_abc123';
$updateData = [
    'status' => 'confirmed'
];

$response = $gophr->updateJob($jobId, $updateData);
$updatedJob = $response->getContentsObject();

echo "Job status: {$updatedJob->status}\n";

Cancelling a Job

$jobId = 'job_abc123';
$cancelData = [
    'reason' => 'Customer requested cancellation'
];

$response = $gophr->cancelJob($jobId, $cancelData);
echo "Job cancelled successfully\n";

Listing Jobs with Pagination

// Get page 2, with 20 jobs per page, including finished jobs
$page = 2;
$count = 20;
$includeFinished = true;

$response = $gophr->listJobs($page, $count, $includeFinished);
$jobs = $response->getContentsArray();

echo "Total jobs: {$jobs['total']}\n";
echo "Current page: {$jobs['current_page']}\n";

foreach ($jobs['data'] as $job) {
    echo "- Job {$job['id']}: {$job['status']}\n";
}

Working with Deliveries

Adding a Delivery to a Job

$jobId = 'job_abc123';

$deliveryData = [
    'pickup' => [
        'earliest_pickup_time' => '2026-08-12T06:17:00+00:00',
        'pickup_deadline' => '2026-08-12T07:13:00+00:00',
        'pickup_address1' => '221B Baker Street',
        'pickup_city' => 'London',
        'pickup_postcode' => 'NW1 6TS',
        'pickup_country_code' => 'GB',
        'pickup_company_name' => 'Gophr',
        'pickup_person_name' => 'John Smith',
        'pickup_email' => 'john@test.com',
        'pickup_mobile_number' => '07700000000',
    ],
    'dropoff' => [
        'dropoff_company_name' => 'Buckingham Palace',
        'dropoff_address1' => 'Buckingham Palace',
        'dropoff_city' => 'London',
        'dropoff_postcode' => 'SW1A 1AA',
        'dropoff_country_code' => 'GB',
        'dropoff_person_name' => 'The Royal Household',
        'dropoff_email' => 'yourmajesty@test.com',
        'dropoff_mobile_number' => '07700000000',
        'dropoff_deadline' => '2026-08-12T08:00:00+00:00',
    ],
    'parcels' => [
        [
            'parcel_external_id' => '003',
            'parcel_reference_number' => '0fc35278-60a1-4fb3-9791-4f45c492e120',
            'parcel_description' => 'Sunglass',
            'width' => 10,
            'length' => 15,
            'height' => 5,
            'weight' => 0.5,
        ],
        [
            'parcel_external_id' => '004',
            'parcel_reference_number' => '0fc35278-60a1-4fb3-9791-4f45c492e120',
            'parcel_description' => 'Folding chair',
            'width' => 50,
            'length' => 80,
            'height' => 5,
            'weight' => 1.5,
        ],
    ],
];

$response = $gophr->createDelivery($jobId, $deliveryData);
$delivery = $response->getContentsObject();

echo "Created Delivery ID: {$delivery->id}\n";

Retrieving a Delivery

$jobId = 'job_abc123';
$deliveryId = 'delivery_xyz789';

$response = $gophr->getDelivery($jobId, $deliveryId);
$delivery = $response->getContentsArray();

print_r($delivery);

Updating a Delivery

$jobId = 'job_abc123';
$deliveryId = 'delivery_xyz789';

$updateData = [
    'dropoff' => [
        'dropoff_phone_number' => '+44 20 7999 8888'  // Update contact phone
    ]
];

$response = $gophr->updateDelivery($jobId, $deliveryId, $updateData);
echo "Delivery updated successfully\n";

Listing Deliveries for a Job

$jobId = 'job_abc123';

$response = $gophr->listDeliveries($jobId);
$deliveries = $response->getContentsArray();

foreach ($deliveries as $delivery) {
    echo "Delivery {$delivery['id']}: {$delivery['status']}\n";
}

Cancelling a Delivery

$jobId = 'job_abc123';
$deliveryId = 'delivery_xyz789';

$cancelData = [
    'reason' => 'Address incorrect'
];

$response = $gophr->cancelDelivery($jobId, $deliveryId, $cancelData);
echo "Delivery cancelled\n";

Working with Parcels

Adding a Parcel to a Delivery

$jobId = 'job_abc123';
$deliveryId = 'delivery_xyz789';

$parcelData = [
    'parcel_external_id' => '005',
    'description' => 'Electronics',
    'weight' => 2.5,        // kg
    'length' => 40,         // cm
    'width' => 30,          // cm
    'height' => 20,         // cm
    'is_fragile' => 1
];

$response = $gophr->createParcel($jobId, $deliveryId, $parcelData);
$parcel = $response->getContentsObject();

echo "Created Parcel ID: {$parcel->id}\n";

Retrieving a Parcel

$jobId = 'job_abc123';
$deliveryId = 'delivery_xyz789';
$parcelId = 'parcel_def456';

$response = $gophr->getParcel($jobId, $deliveryId, $parcelId);
$parcel = $response->getContentsArray();

print_r($parcel);

Updating a Parcel

$jobId = 'job_abc123';
$deliveryId = 'delivery_xyz789';
$parcelId = 'parcel_def456';

$updateData = [
    'weight' => 3.0,  // Update weight
    'is_not_rotatable' => 1 // Mark as non-rotatable
];

$response = $gophr->updateParcel($jobId, $deliveryId, $parcelId, $updateData);
echo "Parcel updated\n";

Listing Parcels in a Delivery

$jobId = 'job_abc123';
$deliveryId = 'delivery_xyz789';

$response = $gophr->listParcels($jobId, $deliveryId);
$parcels = $response->getContentsArray();

foreach ($parcels as $parcel) {
    echo "Parcel {$parcel['id']}: {$parcel['description']} - {$parcel['weight']}kg\n";
}

Deleting a Parcel

$jobId = 'job_abc123';
$deliveryId = 'delivery_xyz789';
$parcelId = 'parcel_def456';

$response = $gophr->deleteParcel($jobId, $deliveryId, $parcelId);
echo "Parcel deleted\n";

// Note: If this was the last parcel, the delivery will be automatically cancelled

Response Handling

All API calls return a GophrResponse object that is PSR-7 compliant.

Getting Response Data

// As an array
$data = $response->getContentsArray();

// As an object
$data = $response->getContentsObject();

// Access specific fields
$jobId = $data['id'];          // Array access
$jobStatus = $data->status;    // Object access

// Get raw response
$rawBody = $response->getBody()->getContents();

// Get status code
$statusCode = $response->getStatusCode();

Response Example

$response = $gophr->getJob('job_abc123');

// Check if successful
if ($response->getStatusCode() === 200) {
    $job = $response->getContentsObject();
    
    echo "Job ID: {$job->id}\n";
    echo "Status: {$job->status}\n";
    echo "Created: {$job->created_at}\n";
    
    // Access nested data
    foreach ($job->deliveries as $delivery) {
        echo "  Delivery: {$delivery->id}\n";
    }
}

Error Handling

Always wrap API calls in try-catch blocks to handle potential errors gracefully.

use Shimango\Gophr\Client;
use Shimango\Gophr\Common\Configuration;

$config = new Configuration('YOUR_API_KEY', true);
$gophr = new Client($config);

try {
    $response = $gophr->getJob('invalid_job_id');
    $job = $response->getContentsArray();
    
} catch (\GuzzleHttp\Exception\ClientException $e) {
    // 4xx errors (client errors)
    $statusCode = $e->getResponse()->getStatusCode();
    $errorBody = $e->getResponse()->getBody()->getContents();
    
    echo "Client Error ({$statusCode}): {$errorBody}\n";
    
} catch (\GuzzleHttp\Exception\ServerException $e) {
    // 5xx errors (server errors)
    echo "Server Error: " . $e->getMessage() . "\n";
    
} catch (\Exception $e) {
    // Other errors
    echo "Error: " . $e->getMessage() . "\n";
}

Common Error Scenarios

// Validation error example
try {
    $jobData = [
        'pickup' => [
            // Missing required fields
        ]
    ];
    
    $response = $gophr->createJob($jobData);
    
} catch (\GuzzleHttp\Exception\ClientException $e) {
    if ($e->getResponse()->getStatusCode() === 422) {
        $errors = json_decode($e->getResponse()->getBody(), true);
        echo "Validation errors:\n";
        print_r($errors['errors']);
    }
}

Testing

Run the test suite:

composer test

Run tests with coverage:

composer test -- --coverage-html coverage

API Reference

For detailed API documentation, request/response schemas, and additional features, visit:

Best Practices

  1. Always use sandbox mode during development:

    $config = new Configuration('test_api_key', true);
  2. Implement proper error handling: Wrap all API calls in try-catch blocks

  3. Validate data before sending: Ensure all required fields are present before making API calls

  4. Store job IDs: Keep track of job IDs in your database for future reference

  5. Don't modify confirmed jobs: Remember that jobs, deliveries, and parcels cannot be modified after confirmation

  6. Use pagination for lists: When retrieving lists of jobs, use pagination to manage large datasets

Support and Resources

License

This library is licensed under the MIT License. See the LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Changelog

See CHANGELOG.md for version history and changes.

shimango/gophr 适用场景与选型建议

shimango/gophr 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 20 次下载、GitHub Stars 达 0, 最近一次更新时间为 2022 年 07 月 24 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「delivery」 「courier」 「shimango」 「gophr」 「last-mile」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 shimango/gophr 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 shimango/gophr 我们能提供哪些服务?
定制开发 / 二次开发

基于 shimango/gophr 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 20
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 23
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 1
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2022-07-24