{"id":41077505,"url":"https://github.com/apacheborys/location-bundle","last_synced_at":"2026-01-22T13:32:09.557Z","repository":{"id":56949238,"uuid":"264389658","full_name":"apacheborys/location-bundle","owner":"apacheborys","description":"Location bundle for manipulate and store places","archived":false,"fork":false,"pushed_at":"2020-07-05T18:40:39.000Z","size":269,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-04-25T05:41:23.581Z","etag":null,"topics":["cache-storage","location","location-based","location-based-services","location-history","location-picker","location-services","location-tracker","location-tracking","locationmanager","locations"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/apacheborys.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-05-16T08:10:37.000Z","updated_at":"2024-04-25T05:41:23.582Z","dependencies_parsed_at":"2022-08-21T03:10:20.157Z","dependency_job_id":null,"html_url":"https://github.com/apacheborys/location-bundle","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/apacheborys/location-bundle","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apacheborys%2Flocation-bundle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apacheborys%2Flocation-bundle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apacheborys%2Flocation-bundle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apacheborys%2Flocation-bundle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/apacheborys","download_url":"https://codeload.github.com/apacheborys/location-bundle/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apacheborys%2Flocation-bundle/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28663786,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-22T01:17:37.254Z","status":"online","status_checked_at":"2026-01-22T02:00:07.137Z","response_time":144,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cache-storage","location","location-based","location-based-services","location-history","location-picker","location-services","location-tracker","location-tracking","locationmanager","locations"],"created_at":"2026-01-22T13:32:08.845Z","updated_at":"2026-01-22T13:32:09.536Z","avatar_url":"https://github.com/apacheborys.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Storage Location Bundle\n---\n[![Build Status](https://travis-ci.com/apacheborys/location-bundle.svg?branch=master)](https://img.shields.io/travis/apacheborys/location-bundle.svg?style=flat-square)\n[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE)\n---\n\nWith that bundle, you will able to build own server of geo data. Manipulation functions:\n\n* [add, delete and update places](#working-with-database)\n* [find place what include specific coordinates point](#find-place-what-include-specific-coordinates-point)\n* [find place by text phrase](#find-place-by-text)\n* [useful functions](#useful-functions)\n\n### Benefits\n\n* save requests to real provider of geo data (if you will use it as cache)\n* own-driven performance control\n* opportunity to build own locations, places\n* possible to use high precise value for coordinates (storing as float type)\n* turnkey solutions for working with places\n\n### Install\n\n```bash\ncomposer require apacheborys/location-bundle\n```\n\n### Usage\n\nFirst of all you need setup storage, where you will save data about locations. Available database providers [here](#database-providers). For example, you can use FilesystemAdapter.\n\n```php\n$database = new \\Symfony\\Component\\Cache\\Adapter\\FilesystemAdapter();\n```\n\nAfter, you need setup database configuration. If you don't want do it, you can use default configuration by creating class without any arguments. Take attention to `useCompression` flag, it can help to save size of storage. If you will use compression, please be sure what your database able to save binary data.\n\n```php\n$dbConfig = new \\ApacheBorys\\Location\\Model\\DBConfig();\n```\n\nAfter that you can use Location bundle:\n\n```php\n$locationBundle = new \\ApacheBorys\\Location\\Location($database, $dbConfig);\n```\n\nPlease take attention what you need to take care for save data in database what you use. Also, in first moment you need to add places what you want, to find that future. Each place in database is specific Place entity, what contain collection of Address entities and properties - `Polygons`, `Bounds`, `timezone`, `providedBy`, `currentLocale` and `objectHash`. Bottom you can see example how you can save information. It just example, don't use it in production please.\n\n```php\n$headers = [\n    'Accept-language' =\u003e 'en'\n];\n\n/* query for Kiev city, Ukraine */\n$query = [\n    'format' =\u003e 'geocodejson',\n    'osm_ids' =\u003e 'R421866',\n    'polygon_geojson' =\u003e 1,\n    'addressdetails' =\u003e 1,\n];\n\n$request = new \\http\\Client\\Request('GET', 'https://nominatim.openstreetmap.org/lookup?' . http_build_query($query), $headers);\n/** @var \\Psr\\Http\\Message\\ResponseInterface $response */\n$response = new \\Http\\Client\\HttpClient($request);\n$rawGeoCodeJson = json_decode((string) $response-\u003egetBody());\n\n$query['format'] = 'geojson';\nunset($query['polygon_geojson'], $query['addressdetails']);\n\n$request = new \\http\\Client\\Request('GET', 'https://nominatim.openstreetmap.org/lookup?' . http_build_query($query), $headers);\n$response = new \\Http\\Client\\HttpClient($request);\n$rawGeoJson = json_decode((string) $response-\u003egetBody());\n\n$rawGeoCodeJson['features'][0]['properties']['common']['bbox'] = $rawGeoJson['features'][0]['bbox'];\n$rawGeoCodeJson['features'][0]['properties']['common']['postcode'] = $rawGeoJson['features'][0]['properties']['address']['postcode'];\n$rawGeoCodeJson['features'][0]['properties']['geocoding']['country_code'] = $rawGeoJson['features'][0]['properties']['address']['country_code'];\n\n$locationBundle-\u003eaddPlace(mapRawDataToPlace($rawGeoCodeJson));\n\nprivate function mapRawDataToPlace(array $rawData): \\ApacheBorys\\Location\\Model\\Place\n{\n    $root = $rawData['features'][0];\n\n    $polygons = [];\n    foreach ($root['geometry']['coordinates'] as $rawPolygon) {\n        $tempPolygon = new \\ApacheBorys\\Location\\Model\\Polygon();\n        foreach ($rawPolygon as $coordinates) {\n            $tempPolygon-\u003eaddCoordinates(new \\ApacheBorys\\Location\\Model\\Coordinates($coordinates[0], $coordinates[1]));\n        }\n        $polygons[] = $tempPolygon;\n    }\n\n    $addresses = [];\n    foreach ($root['properties'] as $locale =\u003e $rawAddress) {\n        if ('common' === $locale) {\n            continue;\n        }\n        $addresses[$locale] = $this-\u003emapRawDataToAddress($rawAddress, $locale);\n    }\n\n    return new \\ApacheBorys\\Location\\Model\\Place(\n        $addresses,\n        $polygons,\n        \\ApacheBorys\\Location\\Model\\Place::DEFAULT_LOCALE,\n        $root['properties']['common']['postcode'],\n        null,\n        $rawData['geocoding']['attribution'],\n        new \\ApacheBorys\\Location\\Model\\Bounds(\n            $root['properties']['common']['bbox'][0],\n            $root['properties']['common']['bbox'][1],\n            $root['properties']['common']['bbox'][2],\n            $root['properties']['common']['bbox'][3]\n        )\n    );\n}\n\nprivate function mapRawDataToAddress(array $rawData, string $locale): \\ApacheBorys\\Location\\Model\\Address\n{\n    $adminLevels = [];\n    foreach ($rawData['geocoding']['admin'] as $adminLevel =\u003e $name) {\n        $level = (int) substr($adminLevel, 5);\n        $adminLevels[$level] = new \\ApacheBorys\\Location\\Model\\AdminLevel($level, $name);\n    }\n\n    return new \\ApacheBorys\\Location\\Model\\Address(\n        $locale,\n        new \\ApacheBorys\\Location\\Model\\AdminLevelCollection($adminLevels),\n        $rawData['geocoding']['housenumber'] ?? '',\n        $rawData['geocoding']['street'] ?? '',\n        $rawData['geocoding']['state'] ?? '',\n        $rawData['geocoding']['city'] ?? '',\n        new \\ApacheBorys\\Location\\Model\\Country($rawData['geocoding']['country'], $rawData['geocoding']['country_code'])\n    );\n}\n```\n\nAfter add place above, you will receive that place in `reverseQuery` for any coordinate what consisting in Place's polygons. If you will add place with highest admin level - you will receive that new place. That provider every time try to respond places with highest admin level (for `reverseQuery` method).\n\n### Find place what include specific coordinates point\n\n```php\n$address = $locationBundle-\u003ereverseQuery(\n    new \\ApacheBorys\\Location\\Query\\ReverseQuery(new \\ApacheBorys\\Location\\Model\\Coordinates(50.4422519, 30.5423135))\n);\n```\n\n### Find place by text\n\nFor `geocodeQuery` use any text what you want to find.\n\n```php\n$address = $locationBundle-\u003egeocodeQuery(new \\ApacheBorys\\Location\\Query\\GeocodeQuery('Kyiv, Ukraine'));\n```\n\n### Useful functions\n\n#### Measuring distance between two coordinates\n\nFor measuring distance, please pass two coordinates to distance method. Please take attention what altitude take to calculation too.\n\n```php\n$distance = $this-\u003elocation-\u003edistance(\n    new \\ApacheBorys\\Location\\Model\\Coordinates(30.520620, 50.455414, 172.6),\n    new \\ApacheBorys\\Location\\Model\\Coordinates(30.557294, 50.434596, 190.8)\n);\n```\n\nIn result, you will get distance in kilometers without rounding. As result, you will have preciseness more than millimeter.\n\n#### Find common points in different places\n\nIf you want to find neighbour Places with one specific Place. It's very easy to use. Also you can find intersected routes for build way.\nYou can try to find all places what contain common points. Please take attention than you can specify places what you want to check as third argument.\n\n```php\n$neighbours = $this-\u003elocation-\u003efindTouchedPlaces(\n    $originalPlace,\n    $maxDistanceToBorder,\n    $specificPlaces\n);\n```\n\nWhere `originalPlace` is Place what we will take as base. And try to find common points from another places.\n`maxDistanceToBorder` is float value for minimum distance to possible common point. As default - 100 meters.\n`specificPlaces` is array of Places. If you will pass some Places in that argument. Location bundle will check only that Places for common points.\n\n### Working with Database\n\nThat bundle has methods for realize database functionality:\n* `addPlace` - add Place object, return boolean\n* `deletePlace` - delete Place object, return boolean\n* `getAllPlaces` - get all existent places in database, return array of `\\ApacheBorys\\Location\\Model\\Place`. Please take attention for pagination.\n\nTake attention what each Place object identified in database according to `objectHash` property. Please use that property as read-only. If you will change that property, database provider will lose relation to that Place in database.\n\nTake attention what each Address object identified in database according:\n1. Admin level - admin level name\n2. Locality, subLocality, streetName, streetNumber\n\nIf you want to change Place entity, you should delete that Place and add new Place with an already changed object. Also, please take attention what each object in database have time to life value (for PSR-6). By default, it's 365 days (1 year), you can setup it through passing specific argument in creation `\\ApacheBorys\\Location\\Model\\DBConfig`.\n\n### Database providers\n\nYou can choose what database provider you want to use. Now available 2 providers:\n* `\\ApacheBorys\\Location\\Database\\PdoDatabase`\n* `\\ApacheBorys\\Location\\Database\\Psr6Database`\n\nAlso, please take attention to `\\ApacheBorys\\Location\\Model\\DBConfig`. You can find a lot config values what make possibility to fine tune.\n\nIf you want to save storage space you can enable compressing data here `\\ApacheBorys\\Location\\Model\\DBConfig::$useCompression`. Please take attention what you can adjust compression level here `\\ApacheBorys\\Location\\Model\\DBConfig::$compressionLevel` (1-9 values, default - 5). Please take attention, what compression performing through commands [gzuncompress](https://www.php.net/manual/en/function.gzuncompress.php) and [gzcompress](https://www.php.net/manual/en/function.gzcompress.php). Please take care for migration data from/to compress state by self.\n\nIf you don't want use data in databases, you should take care for deletion that by self.\n\n#### PdoDatabase\n\nYou can use that provider if you are plan to store your places in sqlite, mysql or postgresql. For constructor, you need to pass `\\PDO` object as first argument. Name of tables what will create on first provider call - `\\ApacheBorys\\Location\\Database\\PdoDatabase\\HelperInterface::queryForCreateTables`.\n\n#### Psr6Database\n\nThat provider is more simple and store data about place entity like a pile in cache. Please take care for data's TTL, because usually each cache (PSR-6) provider have standard TTL value. Also, you can adjust it by specify TTL value for `\\ApacheBorys\\Location\\Model\\DBConfig::$ttlForRecord`, default value is `\\ApacheBorys\\Location\\Model\\DBConfig::TTL_FOR_RECORD`.\n\nFor constructor, you need to pass any object what implement `\\Psr\\Cache\\CacheItemPoolInterface` as first argument.\n\n### Testing\n\nPlease run `composer test`.\n\n### Warning\n\nPlease take attention what each geo data have owner and you should use it only in legitimate goals.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapacheborys%2Flocation-bundle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fapacheborys%2Flocation-bundle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapacheborys%2Flocation-bundle/lists"}