Skip to content

dmgctrlr/lara-osrm

Repository files navigation

Wrapper around OSRM for Laravel

Build Status Latest Version on Packagist PHP Version Minimum License

This package is a simple wrapper for querying OSRM. It assumes you have an OSRM v5.x server available. It supports route, nearest, table, match, and trip services. Driving is the only profile currently supported.

Installation

You can install the package via composer:

composer require dmgctrlr/lara-osrm

Publish the config file (config/lara-osrm.config)

php artisan vendor:publish --tag="config" --provider="Dmgctrlr\LaraOsrm\LaraOsrmServiceProvider"

You can overwrite the defaults in your .env file too:

OSRM_HOST=localhost
OSRM_PORT=5000
OSRM_VERSION=v1

Usage

Getting the Request Service

There are a few ways to get the request service, depending on your preferences and situation.

Direct Creation

You can create them directly - passing an array (including 'host' and 'port' keys if you want to overwrite reading from config()

// Create a ServiceRequest based on the service you want: RouteServiceRequest, MatchServiceRequest, TripServiceRequest
use Dmgctrlr\LaraOsrm\RouteServiceRequest;

// Pass config to overwrite the defaults and your laravel config/lara-osrm.php
$config = [
    'host' => 'localhost', // Hostname of your OSRM server
    'port' => 5000, // Port for your OSRM server
];
$request = new RouteServiceRequest($config);

Dependency Injection

LaraOSRM registers with Laravel's dependency injector - so if you're using LaraOSRM in a controller, job or similar you can simply add it as a requirement. It will be setup using the config settings defined in config/lara-osrm.php and/or .env

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;

use Dmgctrlr\LaraOsrm\LaraOsrm;
use Dmgctrlr\LaraOsrm\Models\LatLng;

class Test extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'lara-osrm:test';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Command description';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle(LaraOsrm $osrm)
    {
        // Create your ServiceRequest based on the method you call
        // e.g. $osrm->route() creates a RouteServiceRequest
        // $osrm->match(), $osrm->trip() etc.
        $request = $osrm->route();
        $request->setCoordinates([
            new LatLng(33.712053, -112.068195),
            new LatLng(33.602053, -112.065295),
            new LatLng(33.626367, -112.023641)
        ]);
        $response = $request->send();
        echo $response->getStatus(); // "Ok"
    }
}

Route Calculation

See: http://project-osrm.org/docs/v5.22.0/api/#route-service

use Dmgctrlr\LaraOsrm\Models\LatLng;

// See (Getting the Request Service)[#getting-the-request-service] to get your $request
$request->setCoordinates([
    new LatLng(33.712053, -112.068195),
    new LatLng(33.602053, -112.065295),
    new LatLng(33.626367, -112.023641)
]);

// you can override the default options for each supported service
// This is the same as calling setOptions() multiple times. Pass each option
// a parameter, use an array if you want to set the value to something other than "true"
$request->setOptions('steps', [ 'annotations' => false ], ['overview' => 'full'], ['geometries' => 'geojson']);

// `send()` returns a Dmgctrlr\LaraOsrm\Responses\RouteServiceResponse (since we made a RouteServiceRequest).
$response = $request->send();
$status = $response->getStatus(); // "Ok"
$status = $response->getMessage(); // Mostly useful for getting the error message if there's a problem.

$routes = $response->getRoutes(); // Returns an array of Dmgctrlr\LaraOsrm\Models\Route

// @var Dmgctrlr\LaraOsrm\Models\Route $recommendedRoute **/
$recommendedRoute = $response->getFirstRoute(); // Returns the first/primary route
$recommendedRoute->getDistance(); // Returns in meters
$recommendedRoute->getDistance('km'); // Returns in kilometers
$recommendedRoute->getDistance('miles', 4); // Returns in miles ronded to 4 decimal places

Match Service

See: http://project-osrm.org/docs/v5.22.0/api/#match-service

use Dmgctrlr\LaraOsrm\Models\LatLng;

// See (Getting the Request Service)[#getting-the-request-service] to get your $request
$request->setCoordinates([
    new LatLng(33.712053, -112.068195),
    new LatLng(33.626367, -112.023641)
]);

// you can override the default options for each supported service
$request->setOptions('steps', 'annotations', ['overview' => 'full'], ['geometries' => 'geojson']);

// `send()` returns a Dmgctrlr\LaraOsrm\Responses\RouteServiceResponse (since we made a RouteServiceRequest).
$response = $request->send();
$status = $response->getStatus(); // "Ok"
$status = $response->getMessage(); // Mostly useful for getting the error message if there's a problem.

$routes = $response->getTracepoints(); // Returns an array of Dmgctrlr\LaraOsrm\Models\LatLng

// @var Dmgctrlr\LaraOsrm\Models\Route $recommendedRoute **/
$recommendedRoute = $response->getFirstRoute(); // Returns the first/primary matching.
$recommendedRoute->getDistance(); // Returns in meters
$recommendedRoute->getDistance('km'); // Returns in kilometers
$recommendedRoute->getDistance('miles', 4); // Returns in milesr ronded to 4 decimal places

SendChunk - sending huge RouteServiceRequests

Note: This is an experimental feature, your contributions are welcome

If you want to a route request with more than a few hundred waypoints you'll run into URI length limits when the library sends a GET request to OSRM.

To workaround that you can use sendChunk() - which is an experimental and incomplete attempt at breaking your huge request into smaller requests and combining them.

To use sendChunk():

  • Read the SendChunk inline documentation (src/BaseServiceRequest.php)
  • Confirm that sendChunk processes and returns the information you want (it doesn't process everything)
  • Simply swap send() with sendChunk() on your RouteRequest object.
  • Test to check that the return from sendChunk() is accurate enough for you.

Known Limitations of sendChunk() (and how to help out)

This is actually a list of things known to (probably) work. The crux of the complexity of sendChunk is in re-combining and stitching together the multiple requests we make.

Ultimately we want to be able to perform a send() and a sendChunk() and get exactly the same result. We can do this by using a test list of Waypoints which is small enough for send() and use really small (e.g. 10 instead of 100) chunk sizes.

The tests are currently all in: RouteServiceTest::testSendChunkReturnsSameAsSend and towards the bottom there are a bunch of commented out asserts. The next step is to make those asserts work, and then declare another bit of the result OK!.

  • sendChunk only works with RouteServiceRequests
  • sendChunk only works when 'geometries' is set to 'geojson'
  • sendChunk only works for the 'waypoints' return value
  • any other returned data shouldn't be trusted (it's probably only partial).
  • sendChunk may not throw an error if you try and mis-use it. Please add error reporting.

Testing

If you get errors like Failed asserting that 429 matches expected 400. or other mentions of code 429 then the server you're using is probably busy (or rate limiting you).

By default the tests will use the OSRM demo server, to use your own or another server cp phpunit.xml.dist phpunit.xml and edit the environment variables.

If you're getting errors about a route not having a distance, and you're using your own server - check the server is properly configured and is not returning non-zero distances. For these tests you must have the "berlin" area installed.

composer test

or (better on Windows):

vendor/bin/phpunit

Changelog

Please see CHANGELOG for more information what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security

If you discover any security related issues, please email [email protected] instead of using the issue tracker.

Credits

License

The MIT License (MIT). Please see License File for more information.

Laravel Package Boilerplate

This package was generated using the Laravel Package Boilerplate.