automapa/map-services 问题修复 & 功能扩展

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

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

automapa/map-services

Composer 安装命令:

composer require automapa/map-services

包简介

PHP SDK for Automapa Map Services REST API — Geocoding, Routing & Address Autocomplete

README 文档

README

European Geocoding, Routing & Address Autocomplete

PHP Versions License: MIT

PHP SDK for the Automapa Map Services REST API. Simplifies integration with geocoding, routing, and address autocomplete services for Europe.

Getting started with your .env file

You will receive a .env file from us containing your API credentials. Place it in the root directory of this repository:

AUTOMAPA_API_KEY=your-key
AUTOMAPA_API_PASSWORD=your-password

Once the .env file is in place, you can test all endpoints against the live API using Docker — no local PHP installation required:

# Run the full test suite (unit + integration) inside Docker
make docker-test

# Run only integration tests (live API calls)
make docker-test-integration

# Run only unit tests (no API calls)
make docker-test-unit

# Run all (phpstan + unit + integration) tests inside Docker
make docker-check

Zero dependencies. The SDK has no runtime Composer dependencies — only ext-curl and ext-json, which are bundled with every standard PHP installation. It is compatible with PHP 8.0 and above.

1. Overview

The SDK covers:

  • Geocoding — convert an address to coordinates and back
  • Routing — calculate routes, distance matrices, and point-order optimization
  • Address autocomplete — suggestions as the user types
  • Google Geocoding API compatibility — optional google response format

For the full list of endpoints and parameters, see the Automapa REST API documentation.

2. Installation

composer require automapa/map-services

Requirements: PHP 8.0+, ext-curl, ext-json.

3. Client configuration

use Automapa\MapServices\ApiClient;
use Automapa\MapServices\Config;

$client = new ApiClient(new Config(
    key: 'YOUR_API_KEY',
    pass: 'YOUR_PASSWORD',
));

4. Session handling

A session is opened automatically (lazy) on the first call that requires authorisation. To open it manually:

$client->session()->generateSession();

5. Available services

Class Methods
PingPong ping()
Session getSalt(), generateSession()
Geocoder geocode(), geocodemulti(), revgeocode(), revgeocodemulti()
Autocomplete search(), searchAddress()
Road getSegmentInfo(), speedCheck(), speedCheckMulti()
RoadPermit add(), overwrite(), remove(), list()
Routes matrix(), optimize(), optimizeQueue(), optimizeQueueResult(), route()
Speed speedReport(), speedReportResult()

Geocoder

geocode() — address to coordinates

$response = $client->geocoder()->geocode(
    city: 'Warsaw',
    street: 'Domaniewska',
    house: '37',
    maxResults: 1,
);
$results = $response->data(); // array of results, each with x, y, city, street, ...

geocodemulti() — batch geocoding (up to 100 addresses)

$response = $client->geocoder()->geocodemulti(
    addresses: [
        ['city' => 'Warsaw', 'street' => 'Domaniewska', 'house' => '37'],
        ['city' => 'Kraków', 'street' => 'Floriańska',  'house' => '1'],
    ],
);
$results = $response->data(); // array of result arrays, one per input address

revgeocode() — coordinates to address

$response = $client->geocoder()->revgeocode(
    point: [21.0073642, 52.18288],
    snapToBld: true,
);
$address = $response->data(); // city, street, house, pcode, ...

revgeocodemulti() — batch reverse geocoding

$response = $client->geocoder()->revgeocodemulti(
    points: [
        [21.0073642, 52.18288],
        [19.9449799, 50.0646501],
    ],
    snapToBld: true,
);
$addresses = $response->data(); // array of address arrays, one per input point

Autocomplete

Address and POI autocomplete — returns suggestions as the user types.

search() — search by phrase

$response = $client->autocomplete()->search(
    query: 'Warsaw Domaniewska 37',
    // types: ['place'],  // optional: 'place', 'poi', or both (null = both)
);

$items = $response->data()['items'];

foreach ($items as $item) {
    echo $item['name'];        // "Domaniewska 37, 02-672 Warsaw"
    echo $item['type'];        // "place"
    echo $item['subtype'];     // "building"
    echo $item['coords']['x']; // longitude (lng)
    echo $item['coords']['y']; // latitude (lat)
}

Each items entry contains: type, subtype, name, province, district, community, place, quarter, street, number, postal_code, coords.{x,y}.

searchAddress() — step-by-step address search

Useful for multi-field address forms (city → street → number → postcode).

$response = $client->autocomplete()->searchAddress(
    query: [
        'city'    => 'Warsaw',
        'street'  => 'Dom',     // partial street name
        'number'  => '',
        'zipcode' => '02-672',
    ],
    source: 'street',             // field being searched: 'place', 'street', 'number', 'zipcode'
    selected: ['city', 'zipcode'],  // optional: fields already confirmed by the user
    // limit: 10,                  // optional: max results (default 10)
);

$items = $response->data()['items'];
// [['city' => 'Warsaw', 'street' => 'Domaniewska', 'zipcode' => '02-672', 'count' => 1]]

Each entry may contain: city, street, number, zipcode, count, and optionally coords.{x,y}.

Note on Autocomplete coordinates: Unlike Geocoder, coordinates are nested: coords.x = longitude, coords.y = latitude.

Routes

Route calculation, distance matrix, and point-order optimisation.

route() — calculate a route

$response = $client->routes()->route(
    points: [
        [21.0073642, 52.2297],  // Warsaw (x=lng, y=lat)
        [18.6282,    54.3520],  // Gdańsk
    ],
    route: [
        'type'    => 'short',  // 'quick' | 'short' | 'optimal'
        'traffic' => true,     // true = take live traffic into account
    ],
    object: ['type' => 'car'],
);

$data = $response->data();
echo round($data['length'] / 1000, 1) . ' km';
echo gmdate('H:i:s', $data['eta']);   // estimated travel time
echo $data['mapurl'];                  // link to map
// $data['desc']  — turn-by-turn manoeuvre list
// $data['tolls'] — toll charges

matrix() — distance / time matrix

$response = $client->routes()->matrix(
    points: [
        [21.0073642, 52.2297],
        [18.6282,    54.3520],
        [16.9252,    52.4064],
    ],
    type: 1,  // 1 = time (minutes), 2 = distance (metres)
);

foreach ($response->data() as $row) {
    echo "Segment {$row['points']}: "
        . round($row['length'] / 1000) . ' km, '
        . $row['duration'] . " min\n";
}

optimize() — synchronous optimisation (max 10 points)

$response = $client->routes()->optimize(
    points:   [[21.0, 52.2], [18.6, 54.4], /* ... */],
    type:     1,      // 1 = time, 2 = distance
    fixedEnd: false,  // true = last point is the destination; false = open end
    object:   ['type' => 'car'],
);

$data = $response->data();
$data['order'];    // optimal index sequence, e.g. "0,3,2,1"
$data['sections']; // segment details: x, y, eta, dist

optimizeQueue() + optimizeQueueResult() — asynchronous optimisation (max 50 points)

// Step 1: submit — each point requires an 'id' field
$response  = $client->routes()->optimizeQueue(
    points:     [['id' => 'Warsaw', 'x' => 21.0, 'y' => 52.2], /* ... */],
    optimizeBy: 'time',  // 'time' or 'distance'
    object:     ['type' => 'car'],
);
$requestId = $response->data()['requestId'];

// Step 2: poll for the result
do {
    sleep(2);
    $result = $client->routes()->optimizeQueueResult(requestId: $requestId);
    $data   = $result->data();
} while ($data['resultReady'] !== true);

$data['optimizedSequence']; // array of point IDs in the optimal order

Road

Query road segment metadata and speed limits. Each method accepts an optional $extra array for any additional API fields; named parameters take priority.

// Road segment information nearest to a point
$response = $client->road()->getSegmentInfo(
    x: 21.00736,
    y: 52.18288,
    distLimit: 50,        // search radius in metres (optional)
    useTolls: 1,          // 1=accept tolls, 0=reject, -1=ignore (optional)
    useHighways: -1,      // 1=accept, 0=reject, -1=ignore (optional)
);
$segment = $response->data()['segment'];   // id, streetName, speedLimit, isToll, …

// Speed limit for a single point
$response = $client->road()->speedCheck(
    x: 15.2154636,
    y: 52.3118895,
    dir: 350,             // direction of travel in degrees (optional)
);
$speedLimit      = $response->data()['speedLimit'];       // cars
$speedLimitTruck = $response->data()['speedLimitTruck'];  // trucks

// Speed limits for up to 100 points in one request
$response = $client->road()->speedCheckMulti(
    points: [
        ['x' => 15.2154636, 'y' => 52.3118895, 'dir' => 350],
        ['x' => 13.8412285, 'y' => 52.3111549],
    ],
);
foreach ($response->data() as $result) {
    echo $result['speedLimit'] . "\n";
}

RoadPermit

Manage road permits (weight/size restrictions) tied to a geographic polygon. Each method accepts an optional $extra array for any additional API fields not listed in the signature.

use Automapa\MapServices\Endpoints\RoadPermit;

$rp = $client->roadPermit(RoadPermit::ROAD_PERMIT_ENVIRONMENT_TEST);

// GeoJSON Polygon (ring must be closed — first === last point)
$poly = [
    'type'        => 'Polygon',
    'coordinates' => [[
        [21.000, 52.220],
        [21.020, 52.220],
        [21.020, 52.240],
        [21.000, 52.240],
        [21.000, 52.220],
    ]],
];

// Create a new permit
$response = $rp->add(
    permissions:           ['tr_tonnage' => 12, 'tr_tonn_axis' => 8.5],
    poly:                  $poly,
    date_start:            '2026-01-01',
    date_end:              '2026-12-31',
    description:           'Weight limit — city centre',
    document_name:         'DOC-001',
    location:              'Warsaw',
    is_valid_after_expiry: false,
    extra:                 ['myCustomField' => 'value'], // forwarded to the API as-is
);
$id = $response->raw()['result']['id'];

// Replace an existing permit
$rp->overwrite(
    id:          $id,
    permissions: ['tr_tonnage' => 24],
    poly:        $poly,
);

// List all permits (optionally filter)
$permits = $rp->list(id: $id);   // $permits->data() — array of permit objects

// Delete a permit
$rp->remove($id);

Available permissions keys: tr_tonnage (total weight, t), tr_tonn_axis (axle load, t), tr_height (m).

Speed

GPS-trace speed-violation analysis — submit a trace asynchronously and poll for results.

speedReport() — submit a GPS trace

$points = [
    ['x' => 21.007, 'y' => 52.230, 't' => 1700000000],
    ['x' => 21.012, 'y' => 52.234, 't' => 1700000060],
    // each point: x = longitude, y = latitude, t = Unix timestamp
];

$response  = $client->speed()->speedReport(
    objID:    'VEHICLE-001',
    objName:  'Van 1',
    objGroup: 'Fleet',
    points:   $points,
);
$requestID = $response->data()['requestID'];

speedReportResult() — poll for the analysis result

do {
    sleep(5);
    $result = $client->speed()->speedReportResult(requestID: $requestID);
    $data   = $result->data();
} while ($data['progress'] < 1.0);

foreach ($data['overspeedingArray'] as $violation) {
    echo $violation['startLocation'] . '' . $violation['endLocation'] . "\n";
    echo '  speed: ' . $violation['speedMax'] . ' km/h, limit: ' . $violation['speedLimit'] . " km/h\n";
}
// $data['reportURL'] — link to the full report

Each overspeedingArray entry contains: duration (s), length (m), type (category 1–6), speedMax, speedAvg (km/h), speedLimit (km/h), urbanArea, startLocation, startPoint.{x,y}, endLocation, endPoint.{x,y}, startTime, endTime (Unix timestamps).

The optional limit parameter (default 1) sets the minimum violation category to include (1–6).

6. Examples

# Copy configuration
cp .env.example .env
# Fill in AUTOMAPA_API_KEY and AUTOMAPA_API_PASSWORD in .env

# Routes
php examples/routes-route.php                # point-to-point route
php examples/routes-matrix.php               # distance/time matrix
php examples/routes-optimize.php             # sync optimisation (max 10 points)
php examples/routes-optimize-async.php       # async optimisation (max 50 points)

# Geocoder
php examples/geocoder-geocode.php            # single address → coordinates
php examples/geocoder-geocodemulti.php       # batch address geocoding
php examples/geocoder-revgeocode.php         # coordinates → single address
php examples/geocoder-revgeocodemulti.php    # coordinates → multiple addresses

# Autocomplete
php examples/autocomplete-search.php         # search places and POI by phrase
php examples/autocomplete-search-address.php # search address objects

# Road
php examples/road-segment-info.php           # road segment metadata
php examples/road-speed-check.php            # speed limit for a single point
php examples/road-speed-check-multi.php      # speed limits for multiple points

# Road permits
php examples/road-permit-list.php            # list permits
php examples/road-permit-add.php             # create a new permit
php examples/road-permit-overwrite.php <id>  # replace an existing permit
php examples/road-permit-remove.php <id>     # delete a permit

# Speed reports
php examples/speed-report.php                # submit async speed report
php examples/speed-report-result.php <id>    # poll for report results

or simply run make examples to run all examples.

7. Passing additional parameters

The SDK does not restrict unknown parameters — all fields are forwarded to the API as-is. Every endpoint accepts an $extra array as its last argument. Named params always take priority over $extra:

// Autocomplete
$client->autocomplete()->search(
    query: 'Warsaw',
    extra: ['myCustomParam' => 'value'],
);

// Speed (named params override $extra when the same key appears in both)
$client->speed()->speedReport(
    objID: 'VEHICLE-001',
    objName: 'Van 1',
    objGroup: 'Fleet',
    points: $points,
    extra: ['myCustomParam' => 'value'],
);

8. Low-level call() and request()

// Via service + method name (preferred)
$client->call('Geocoder', 'newMethod', ['param' => 'value']);

// Or via full URL path (fallback)
$client->request('POST', '/v3/Geocoder/newMethod', ['param' => 'value']);

9. Response formats: native vs google

// Native format (default)
$response = $client->geocoder()->geocode(city: 'Kraków');
$data = $response->data();   // API data
$raw  = $response->raw();    // full raw response (always available)

// Google format
$response = $client->geocoder()->geocode(city: 'Kraków', extra: ['format' => 'google']);

10. Google format field limitations

Google field Value
geometry.viewport always null (not provided by the API)
place_id always null (not provided by the API)

Note: The Automapa API uses x = longitude and y = latitude — the opposite of Google's convention.

11. Error handling

Situation Exception class
Invalid API key / password AuthenticationException
Expired session SessionException
Parameter validation failure ValidationException
Resource not found NotFoundException
Rate limit exceeded RateLimitException
Network / cURL error NetworkException
Server error (5xx) ServerException
Unexpected response UnknownResponseException
use Automapa\MapServices\Exception\AuthenticationException;
use Automapa\MapServices\Exception\AutomapaException;

try {
    $response = $client->geocoder()->geocode(city: 'Warsaw');
} catch (AuthenticationException $e) {
    echo 'Authentication error: ' . $e->getMessage();
} catch (AutomapaException $e) {
    echo 'API error: ' . $e->getMessage();
}

License

MIT © 2026 Automapa sp. z o.o.

统计信息

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

GitHub 信息

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

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-06-25

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固