apacheborys/location-bundle

用于操作和存储地点的地点包

2.1 2020-06-28 17:01 UTC

This package is auto-updated.

Last update: 2024-09-06 03:46:45 UTC


README

Build Status Software License

使用此包,您可以构建自己的地理数据服务器。操作功能

优点

  • 节省对真实地理数据提供者的请求(如果您将其用作缓存)
  • 自己驱动的性能控制
  • 有机会构建自己的地点、地点
  • 可以使用高精度的坐标值(以浮点类型存储)
  • 与地点工作的成品解决方案

安装

composer require apacheborys/location-bundle

用法

首先,您需要设置存储,其中将保存有关位置的数据库。可用的数据库提供者这里。例如,您可以使用FilesystemAdapter。

$database = new \Symfony\Component\Cache\Adapter\FilesystemAdapter();

之后,您需要设置数据库配置。如果您不想这样做,您可以通过创建不带任何参数的类来使用默认配置。注意useCompression标志,它可以帮助节省存储空间。如果您将使用压缩,请确保您的数据库能够保存二进制数据。

$dbConfig = new \ApacheBorys\Location\Model\DBConfig();

之后,您就可以使用Location bundle了

$locationBundle = new \ApacheBorys\Location\Location($database, $dbConfig);

请注意,您需要关注您使用的数据库中保存的数据。此外,在最初,您需要添加您想要查找的未来地点。数据库中的每个地点都是一个特定的Place实体,它包含Address实体的集合和属性 - PolygonsBoundstimezoneprovidedBycurrentLocaleobjectHash。下面是一个如何保存信息的示例。这只是示例,请勿在生产环境中使用。

$headers = [
    'Accept-language' => 'en'
];

/* query for Kiev city, Ukraine */
$query = [
    'format' => 'geocodejson',
    'osm_ids' => 'R421866',
    'polygon_geojson' => 1,
    'addressdetails' => 1,
];

$request = new \http\Client\Request('GET', 'https://nominatim.openstreetmap.org/lookup?' . http_build_query($query), $headers);
/** @var \Psr\Http\Message\ResponseInterface $response */
$response = new \Http\Client\HttpClient($request);
$rawGeoCodeJson = json_decode((string) $response->getBody());

$query['format'] = 'geojson';
unset($query['polygon_geojson'], $query['addressdetails']);

$request = new \http\Client\Request('GET', 'https://nominatim.openstreetmap.org/lookup?' . http_build_query($query), $headers);
$response = new \Http\Client\HttpClient($request);
$rawGeoJson = json_decode((string) $response->getBody());

$rawGeoCodeJson['features'][0]['properties']['common']['bbox'] = $rawGeoJson['features'][0]['bbox'];
$rawGeoCodeJson['features'][0]['properties']['common']['postcode'] = $rawGeoJson['features'][0]['properties']['address']['postcode'];
$rawGeoCodeJson['features'][0]['properties']['geocoding']['country_code'] = $rawGeoJson['features'][0]['properties']['address']['country_code'];

$locationBundle->addPlace(mapRawDataToPlace($rawGeoCodeJson));

private function mapRawDataToPlace(array $rawData): \ApacheBorys\Location\Model\Place
{
    $root = $rawData['features'][0];

    $polygons = [];
    foreach ($root['geometry']['coordinates'] as $rawPolygon) {
        $tempPolygon = new \ApacheBorys\Location\Model\Polygon();
        foreach ($rawPolygon as $coordinates) {
            $tempPolygon->addCoordinates(new \ApacheBorys\Location\Model\Coordinates($coordinates[0], $coordinates[1]));
        }
        $polygons[] = $tempPolygon;
    }

    $addresses = [];
    foreach ($root['properties'] as $locale => $rawAddress) {
        if ('common' === $locale) {
            continue;
        }
        $addresses[$locale] = $this->mapRawDataToAddress($rawAddress, $locale);
    }

    return new \ApacheBorys\Location\Model\Place(
        $addresses,
        $polygons,
        \ApacheBorys\Location\Model\Place::DEFAULT_LOCALE,
        $root['properties']['common']['postcode'],
        null,
        $rawData['geocoding']['attribution'],
        new \ApacheBorys\Location\Model\Bounds(
            $root['properties']['common']['bbox'][0],
            $root['properties']['common']['bbox'][1],
            $root['properties']['common']['bbox'][2],
            $root['properties']['common']['bbox'][3]
        )
    );
}

private function mapRawDataToAddress(array $rawData, string $locale): \ApacheBorys\Location\Model\Address
{
    $adminLevels = [];
    foreach ($rawData['geocoding']['admin'] as $adminLevel => $name) {
        $level = (int) substr($adminLevel, 5);
        $adminLevels[$level] = new \ApacheBorys\Location\Model\AdminLevel($level, $name);
    }

    return new \ApacheBorys\Location\Model\Address(
        $locale,
        new \ApacheBorys\Location\Model\AdminLevelCollection($adminLevels),
        $rawData['geocoding']['housenumber'] ?? '',
        $rawData['geocoding']['street'] ?? '',
        $rawData['geocoding']['state'] ?? '',
        $rawData['geocoding']['city'] ?? '',
        new \ApacheBorys\Location\Model\Country($rawData['geocoding']['country'], $rawData['geocoding']['country_code'])
    );
}

添加上述地点后,您将在reverseQuery中收到该地点的任何包含在地点的多边形中的坐标。如果您添加具有最高行政级别的地点,您将收到新的地点。该提供者每次都会尝试为reverseQuery方法提供具有最高行政级别的地点。

查找包含特定坐标点的地点

$address = $locationBundle->reverseQuery(
    new \ApacheBorys\Location\Query\ReverseQuery(new \ApacheBorys\Location\Model\Coordinates(50.4422519, 30.5423135))
);

通过文本查找地点

对于geocodeQuery,请使用您想要查找的任何文本。

$address = $locationBundle->geocodeQuery(new \ApacheBorys\Location\Query\GeocodeQuery('Kyiv, Ukraine'));

有用功能

测量两个坐标之间的距离

为了测量距离,请将两个坐标传递给distance方法。请注意,高度也用于计算。

$distance = $this->location->distance(
    new \ApacheBorys\Location\Model\Coordinates(30.520620, 50.455414, 172.6),
    new \ApacheBorys\Location\Model\Coordinates(30.557294, 50.434596, 190.8)
);

结果,您将得到未经四舍五入的公里数。结果,您将拥有超过毫米的精度。

在不同的地点中找到共同点

如果您想要找到与一个特定地点相邻的地点,这很容易做到。您还可以找到用于构建路径的交叉路线。您可以尝试找到包含共同点的所有地点。请注意,您可以指定要检查的地点作为第三个参数。

$neighbours = $this->location->findTouchedPlaces(
    $originalPlace,
    $maxDistanceToBorder,
    $specificPlaces
);

其中originalPlace是我们将用作基础的地点。并尝试从其他地点中找到共同点。maxDistanceToBorder是到可能的共同点的最小距离的浮点值。默认值为100米。specificPlaces是地点数组。如果您将一些地点传递给该参数,Location bundle将只检查该参数中的地点以查找共同点。

与数据库一起工作

该包具有实现数据库功能的方法

  • addPlace - 添加Place对象,返回布尔值
  • deletePlace - 删除地点对象,返回布尔值
  • getAllPlaces - 获取数据库中所有存在的地点,返回 \ApacheBorys\Location\Model\Place 对象数组。请注意分页。

请注意,数据库中每个地点对象都是根据 objectHash 属性进行标识的。请将该属性用作只读属性。如果您更改该属性,数据库提供程序将丢失与数据库中该地点的关系。

请注意,每个地址对象在数据库中的标识方式

  1. 管理员级别 - 管理员级别名称
  2. 地区、子地区、街道名称、街道号码

如果您想更改地点实体,应该删除该地点,然后添加一个新的地点,该地点包含已更改的对象。同时,请注意,数据库中的每个对象都有生命周期值(对于 PSR-6)。默认值为 365 天(1 年),您可以通过在创建 \ApacheBorys\Location\Model\DBConfig 时传递特定参数来设置它。

数据库提供程序

您可以选择要使用的数据库提供程序。现在有 2 个提供程序可用

  • \ApacheBorys\Location\Database\PdoDatabase
  • \ApacheBorys\Location\Database\Psr6Database

同时,请注意 \ApacheBorys\Location\Model\DBConfig。您可以在其中找到许多配置值,这些值可以提供微调的可能性。

如果您想节省存储空间,可以在此处启用数据压缩 \ApacheBorys\Location\Model\DBConfig::$useCompression。请注意,您可以在此处调整压缩级别 \ApacheBorys\Location\Model\DBConfig::$compressionLevel(1-9 个值,默认为 5)。请注意,压缩通过命令 gzuncompressgzcompress 执行。请注意,数据在压缩状态之间迁移时自行处理。

如果您不想在数据库中使用数据,应该自行处理删除。

PdoDatabase

如果您计划将地点存储在 sqlite、mysql 或 postgresql 中,可以使用此提供程序。对于构造函数,您需要将 \PDO 对象作为第一个参数传递。在第一次调用提供程序时将创建的表名称 - \ApacheBorys\Location\Database\PdoDatabase\HelperInterface::queryForCreateTables

Psr6Database

此提供程序更简单,将地点实体的数据存储在缓存中。请注意数据的有效时间(TTL),因为通常每个缓存(PSR-6)提供程序都有标准的 TTL 值。您还可以通过指定 \ApacheBorys\Location\Model\DBConfig::$ttlForRecord 的 TTL 值来调整它,默认值为 \ApacheBorys\Location\Model\DBConfig::TTL_FOR_RECORD

对于构造函数,您需要将实现 \Psr\Cache\CacheItemPoolInterface 的任何对象作为第一个参数传递。

测试

请运行 composer test

警告

请注意,每个地理数据都有所有者,并且您只能用于合法目的。