├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ └── config.yml └── workflows │ ├── php-cs-fixer.yml │ ├── update-changelog.yml │ └── run-tests.yml ├── .editorconfig ├── src ├── Facades │ └── Geocoder.php ├── Exceptions │ └── CouldNotGeocode.php ├── GeocoderServiceProvider.php └── Geocoder.php ├── LICENSE ├── config └── geocoder.php ├── .php-cs-fixer.dist.php ├── composer.json ├── CHANGELOG.md └── README.md /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | custom: https://spatie.be/open-source/support-us 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | contact_links: 3 | - name: Feature Request 4 | url: https://github.com/spatie/geocoder/discussions/new?category=ideas 5 | about: Share ideas for new features 6 | - name: Ask a Question 7 | url: https://github.com/spatie/geocoder/discussions/new?category=q-a 8 | about: Ask the community for help 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | ; This file is for unifying the coding style for different editors and IDEs. 2 | ; More information at http://editorconfig.org 3 | 4 | root = true 5 | 6 | [*] 7 | charset = utf-8 8 | indent_size = 4 9 | indent_style = space 10 | end_of_line = lf 11 | insert_final_newline = true 12 | trim_trailing_whitespace = true 13 | 14 | [*.md] 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /src/Facades/Geocoder.php: -------------------------------------------------------------------------------- 1 | publishes([ 13 | __DIR__.'/../config/geocoder.php' => config_path('geocoder.php'), 14 | ], 'config'); 15 | } 16 | 17 | public function register() 18 | { 19 | $this->mergeConfigFrom(__DIR__.'/../config/geocoder.php', 'geocoder'); 20 | 21 | $this->app->bind('geocoder', function ($app) { 22 | $client = app(Client::class); 23 | 24 | return (new Geocoder($client)) 25 | ->setApiKey(config('geocoder.key')) 26 | ->setLanguage(config('geocoder.language')) 27 | ->setRegion(config('geocoder.region')) 28 | ->setBounds(config('geocoder.bounds')) 29 | ->setCountry(config('geocoder.country')); 30 | }); 31 | 32 | $this->app->bind(Geocoder::class, 'geocoder'); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Spatie bvba 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /config/geocoder.php: -------------------------------------------------------------------------------- 1 | env('GOOGLE_MAPS_GEOCODING_API_KEY', ''), 9 | 10 | /* 11 | * The language param used to set response translations for textual data. 12 | * 13 | * More info: https://developers.google.com/maps/faq#languagesupport 14 | */ 15 | 16 | 'language' => '', 17 | 18 | /* 19 | * The region param used to finetune the geocoding process. 20 | * 21 | * More info: https://developers.google.com/maps/documentation/geocoding/requests-geocoding#RegionCodes 22 | */ 23 | 'region' => '', 24 | 25 | /* 26 | * The bounds param used to finetune the geocoding process. 27 | * 28 | * More info: https://developers.google.com/maps/documentation/geocoding/requests-geocoding#Viewports 29 | */ 30 | 'bounds' => '', 31 | 32 | /* 33 | * The country param used to limit results to a specific country. 34 | * 35 | * More info: https://developers.google.com/maps/documentation/javascript/geocoding#GeocodingRequests 36 | */ 37 | 'country' => '', 38 | 39 | ]; 40 | -------------------------------------------------------------------------------- /.php-cs-fixer.dist.php: -------------------------------------------------------------------------------- 1 | in([ 5 | __DIR__ . '/src', 6 | __DIR__ . '/tests', 7 | ]) 8 | ->name('*.php') 9 | ->ignoreDotFiles(true) 10 | ->ignoreVCS(true); 11 | 12 | return (new PhpCsFixer\Config()) 13 | ->setRules([ 14 | '@PSR12' => true, 15 | 'array_syntax' => ['syntax' => 'short'], 16 | 'ordered_imports' => ['sort_algorithm' => 'alpha'], 17 | 'no_unused_imports' => true, 18 | 'not_operator_with_successor_space' => true, 19 | 'trailing_comma_in_multiline' => true, 20 | 'phpdoc_scalar' => true, 21 | 'unary_operator_spaces' => true, 22 | 'binary_operator_spaces' => true, 23 | 'blank_line_before_statement' => [ 24 | 'statements' => ['break', 'continue', 'declare', 'return', 'throw', 'try'], 25 | ], 26 | 'phpdoc_single_line_var_spacing' => true, 27 | 'phpdoc_var_without_name' => true, 28 | 'class_attributes_separation' => [ 29 | 'elements' => [ 30 | 'method' => 'one', 31 | ], 32 | ], 33 | 'method_argument_space' => [ 34 | 'on_multiline' => 'ensure_fully_multiline', 35 | 'keep_multiple_spaces_after_comma' => true, 36 | ], 37 | 'single_trait_insert_per_statement' => true, 38 | ]) 39 | ->setFinder($finder); -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "spatie/geocoder", 3 | "description": "Geocoding addresses to coordinates", 4 | "homepage": "https://github.com/spatie/geocoder", 5 | "keywords": [ 6 | "geocode", 7 | "map", 8 | "coordinate", 9 | "location", 10 | "laravel" 11 | ], 12 | "license": "MIT", 13 | "authors": [ 14 | { 15 | "name": "Freek Van der Herten", 16 | "email": "freek@spatie.be" 17 | } 18 | ], 19 | "require": { 20 | "php": "^7.2|^8.0", 21 | "illuminate/support": "^6.0|^7.0|^8.67|^9.0|^10.0|^11.0|^12.0", 22 | "guzzlehttp/guzzle": "^6.5|^7.0" 23 | }, 24 | "require-dev": { 25 | "phpunit/phpunit": "^8.5.21|^9.0|^9.4.4|^10.5|^11.5.3", 26 | "orchestra/testbench": "^4.0|^5.0|^6.0|^8.0|^9.0|^10.0" 27 | }, 28 | "autoload": { 29 | "psr-4": { 30 | "Spatie\\Geocoder\\": "src" 31 | } 32 | }, 33 | "autoload-dev": { 34 | "psr-4": { 35 | "Spatie\\Geocoder\\Tests\\": "tests" 36 | } 37 | }, 38 | "scripts": { 39 | "test": "vendor/bin/phpunit" 40 | }, 41 | "extra": { 42 | "laravel": { 43 | "providers": [ 44 | "Spatie\\Geocoder\\GeocoderServiceProvider" 45 | ], 46 | "aliases": { 47 | "Geocoder": "Spatie\\Geocoder\\Facades\\Geocoder" 48 | } 49 | } 50 | }, 51 | "minimum-stability": "dev", 52 | "prefer-stable": true 53 | } 54 | -------------------------------------------------------------------------------- /.github/workflows/run-tests.yml: -------------------------------------------------------------------------------- 1 | name: run-tests 2 | 3 | on: 4 | - push 5 | - pull_request 6 | 7 | jobs: 8 | test: 9 | runs-on: ${{ matrix.os }} 10 | 11 | strategy: 12 | fail-fast: false 13 | matrix: 14 | os: [ubuntu-latest] 15 | php: [8.4, 8.3, 8.2, 8.1, 8.0] 16 | laravel: ['9.*', '10.*', '11.*', '12.*'] 17 | dependency-version: [prefer-stable] 18 | include: 19 | - laravel: 10.* 20 | testbench: 8.* 21 | - laravel: 9.* 22 | testbench: 7.* 23 | - laravel: 11.* 24 | testbench: 9.* 25 | - laravel: 12.* 26 | testbench: 10.* 27 | exclude: 28 | - laravel: 10.* 29 | php: 8.0 30 | - laravel: 11.* 31 | php: 8.1 32 | - laravel: 11.* 33 | php: 8.0 34 | - laravel: 12.* 35 | php: 8.1 36 | - laravel: 12.* 37 | php: 8.0 38 | 39 | name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.dependency-version }} - ${{ matrix.os }} 40 | 41 | steps: 42 | - name: Checkout code 43 | uses: actions/checkout@v3 44 | 45 | - name: Cache dependencies 46 | uses: actions/cache@v1 47 | with: 48 | path: ~/.composer/cache/files 49 | key: dependencies-laravel-${{ matrix.laravel }}-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }} 50 | 51 | - name: Setup PHP 52 | uses: shivammathur/setup-php@v2 53 | with: 54 | php-version: ${{ matrix.php }} 55 | extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick 56 | coverage: none 57 | 58 | - name: Install dependencies 59 | run: | 60 | composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update 61 | composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction --no-suggest 62 | 63 | - name: Execute tests 64 | run: vendor/bin/phpunit 65 | env: 66 | GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }} 67 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `geocoder` will be documented in this file. 4 | 5 | ## 3.16.2 - 2025-11-20 6 | 7 | ### What's Changed 8 | 9 | * Update issue template by @AlexVanderbist in https://github.com/spatie/geocoder/pull/116 10 | * Update docblock for `getCoordinatesForAddress` 11 | 12 | **Full Changelog**: https://github.com/spatie/geocoder/compare/3.16.1...3.16.2 13 | 14 | ## 3.16.1 - 2025-02-21 15 | 16 | ### What's Changed 17 | 18 | * Laravel 12.x Compatibility by @laravel-shift in https://github.com/spatie/geocoder/pull/115 19 | 20 | **Full Changelog**: https://github.com/spatie/geocoder/compare/3.16.0...3.16.1 21 | 22 | ## 3.16.0 - 2024-03-02 23 | 24 | ### What's Changed 25 | 26 | * Laravel 11.x Compatibility by @laravel-shift in https://github.com/spatie/geocoder/pull/113 27 | 28 | **Full Changelog**: https://github.com/spatie/geocoder/compare/3.15.0...3.16.0 29 | 30 | ## 3.15.0 - 2023-10-17 31 | 32 | ### What's Changed 33 | 34 | - Return types by @francoism90 in https://github.com/spatie/geocoder/pull/112 35 | 36 | ### New Contributors 37 | 38 | - @francoism90 made their first contribution in https://github.com/spatie/geocoder/pull/112 39 | 40 | **Full Changelog**: https://github.com/spatie/geocoder/compare/3.14.2...3.15.0 41 | 42 | ## 3.14.2 - 2023-02-01 43 | 44 | ### What's Changed 45 | 46 | - Fixes the example for a specific language by @hofmannsven in https://github.com/spatie/geocoder/pull/107 47 | - Add PHP 8.2 Support by @patinthehat in https://github.com/spatie/geocoder/pull/108 48 | - Laravel 10.x Compatibility by @laravel-shift in https://github.com/spatie/geocoder/pull/110 49 | 50 | ### New Contributors 51 | 52 | - @hofmannsven made their first contribution in https://github.com/spatie/geocoder/pull/107 53 | - @patinthehat made their first contribution in https://github.com/spatie/geocoder/pull/108 54 | - @laravel-shift made their first contribution in https://github.com/spatie/geocoder/pull/110 55 | 56 | **Full Changelog**: https://github.com/spatie/geocoder/compare/3.14.1...3.14.2 57 | 58 | ## 3.14.1 - 2022-06-29 59 | 60 | - fix `partial_match` error 61 | 62 | ## 3.14.0 - 2022-06-28 63 | 64 | ### What's Changed 65 | 66 | - Update formatResponse to include partial_match by @MultiSuperFreek in https://github.com/spatie/geocoder/pull/103 67 | 68 | ### New Contributors 69 | 70 | - @MultiSuperFreek made their first contribution in https://github.com/spatie/geocoder/pull/103 71 | 72 | **Full Changelog**: https://github.com/spatie/geocoder/compare/3.13.1...3.14.0 73 | 74 | ## 3.13.1 - 2022-06-26 75 | 76 | ### What's Changed 77 | 78 | - Update Geocoding API doc url by @newjett0617 in https://github.com/spatie/geocoder/pull/102 79 | 80 | ### New Contributors 81 | 82 | - @newjett0617 made their first contribution in https://github.com/spatie/geocoder/pull/102 83 | 84 | **Full Changelog**: https://github.com/spatie/geocoder/compare/3.13.0...3.13.1 85 | 86 | ## 3.13.0 - 2022-05-18 87 | 88 | **Full Changelog**: https://github.com/spatie/geocoder/compare/3.12.0...3.13.0 89 | 90 | ## 3.12.0 - 2022-02-09 91 | 92 | ## What's Changed 93 | 94 | - Support illuminate/support 9.0 by @austenc in https://github.com/spatie/geocoder/pull/99 95 | 96 | ## New Contributors 97 | 98 | - @austenc made their first contribution in https://github.com/spatie/geocoder/pull/99 99 | 100 | **Full Changelog**: https://github.com/spatie/geocoder/compare/3.11.0...3.12.0 101 | 102 | ## 3.11.0 - 2021-11-18 103 | 104 | - Add support for PHP 8.1 105 | 106 | **Full Changelog**: https://github.com/spatie/geocoder/compare/3.10.1...3.11.0 107 | 108 | ## 3.10.1 - 2020-12-02 109 | 110 | - revert previous version 111 | 112 | ## 3.10.0 - 2020-12-01 113 | 114 | - add `plus_code` to formatted response (#91) 115 | 116 | ## 3.9.3 - 2020-12-01 117 | 118 | - Add support for PHP 8.0 ([#90](https://github.com/spatie/geocoder/pull/90)) 119 | 120 | ## 3.9.2 - 2020-09-09 121 | 122 | - Add support for Laravel 8 123 | 124 | ## 3.9.1 - 2020-08-06 125 | 126 | - add ability to resolve Geocoder from the fully qualified class name (#87) 127 | 128 | ## 3.9.0 - 2020-07-27 129 | 130 | - return multiple results for reverse-geocoding (#86) 131 | 132 | ## 3.8.1 - 2020-07-01 133 | 134 | - allow Guzzle 7 135 | 136 | ## 3.8.0 - 2020-05-11 137 | 138 | - return multiple results as array rather than just the first one (#73) 139 | 140 | ## 3.7.0 - 2020-03-04 141 | 142 | - add support for Laravel 7 143 | 144 | ## 3.6.1 - 2019-01-04 145 | 146 | - improve testability by resolving the guzzle client out of the container 147 | 148 | ## 3.6.0 - 2019-09-04 149 | 150 | - add support for Laravel 6 151 | 152 | ## 3.5.0 - 2019-05-31 153 | 154 | - add country parameter 155 | - drop support for PHP 7.1 and smaller 156 | 157 | ## 3.4.0 - 2018-01-24 158 | 159 | - include address components in the response 160 | 161 | ## 3.3.1 - 2018-05-15 162 | 163 | - fix PHP 7.0 requirement in composer.json 164 | 165 | ## 3.3.0 - 2018-04-20 166 | 167 | - add support for setting bounds 168 | 169 | ## 3.2.0 - 2018-03-30 170 | 171 | - add viewport coordinates to `Geocoder::formatResponse()` 172 | 173 | ## 3.1.1 - 2018-02-21 174 | 175 | - improved exception handling 176 | 177 | ## 3.1.0 - 2017-10-25 178 | 179 | - add `getAddressForCoordinates` 180 | 181 | ## 3.0.1 - 2017-10-24 182 | 183 | - fix typo 184 | 185 | ## 3.0.0 - 2017-10-24 186 | 187 | - dropped support for PHP 5 188 | - cleaned up internals 189 | - some small API changes 190 | 191 | ## 2.3.2 - 2016-11-15 192 | 193 | - require Guzzle 6 instead of 5 194 | 195 | ## 2.3.1 - 2016-09-04 196 | 197 | - fixed the naming of variables in the `Geocoder` interface 198 | 199 | ### 2.3.0 - 2016-09-01 200 | 201 | - added support for regions and languages 202 | - added Laravel integration 203 | 204 | ### 2.2.0 - 2016-08-20 205 | 206 | - add `formatted_address` to result 207 | 208 | ### 2.1.3 - 2016-08-07 209 | 210 | - remove `sensor` parameter 211 | 212 | ### 2.1.2 - 2016-07-04 213 | 214 | - upgrade Guzzle version 215 | 216 | ### 2.1.1 - 2016-03-10 217 | 218 | - use HTTPS to connect to google 219 | -------------------------------------------------------------------------------- /src/Geocoder.php: -------------------------------------------------------------------------------- 1 | client = $client; 36 | } 37 | 38 | public function setApiKey(string $apiKey) 39 | { 40 | $this->apiKey = $apiKey; 41 | 42 | return $this; 43 | } 44 | 45 | public function setLanguage(string $language) 46 | { 47 | $this->language = $language; 48 | 49 | return $this; 50 | } 51 | 52 | public function setRegion(string $region) 53 | { 54 | $this->region = $region; 55 | 56 | return $this; 57 | } 58 | 59 | public function setBounds(string $bounds) 60 | { 61 | $this->bounds = $bounds; 62 | 63 | return $this; 64 | } 65 | 66 | public function setCountry(string $country) 67 | { 68 | $this->country = $country; 69 | 70 | return $this; 71 | } 72 | 73 | /** 74 | * @return array{ 75 | * lat: float, 76 | * lng: float, 77 | * accuracy: string, 78 | * formatted_address: string, 79 | * viewport: object{northeast: object{lat: float, lng: float}, southwest: object{lat: float, lng: float}}, 80 | * address_components: array}>, 81 | * partial_match: bool, 82 | * place_id: string, 83 | * types: array 84 | * } 85 | */ 86 | public function getCoordinatesForAddress(string $address): array 87 | { 88 | $response = $this->getAllCoordinatesForAddress($address); 89 | 90 | return $response[0]; 91 | } 92 | 93 | /** 94 | * @return array}>, 101 | * partial_match: bool, 102 | * place_id: string, 103 | * types: array 104 | * }> 105 | */ 106 | public function getAllCoordinatesForAddress(string $address): array 107 | { 108 | if (empty($address)) { 109 | return $this->emptyResponse(); 110 | } 111 | 112 | $payload = $this->getRequestPayload(compact('address')); 113 | $response = $this->client->request('GET', $this->endpoint, $payload); 114 | 115 | if ($response->getStatusCode() !== 200) { 116 | throw CouldNotGeocode::couldNotConnect(); 117 | } 118 | 119 | $geocodingResponse = json_decode($response->getBody()); 120 | 121 | if (! empty($geocodingResponse->error_message)) { 122 | throw CouldNotGeocode::serviceReturnedError($geocodingResponse->error_message); 123 | } 124 | 125 | if (! count($geocodingResponse->results)) { 126 | return $this->emptyResponse(); 127 | } 128 | 129 | return $this->formatResponse($geocodingResponse); 130 | } 131 | 132 | public function getAddressForCoordinates(float $lat, float $lng): array 133 | { 134 | $response = $this->getAllAddressesForCoordinates($lat, $lng); 135 | 136 | return $response[0]; 137 | } 138 | 139 | public function getAllAddressesForCoordinates(float $lat, float $lng): array 140 | { 141 | $payload = $this->getRequestPayload([ 142 | 'latlng' => "$lat,$lng", 143 | ]); 144 | 145 | $response = $this->client->request('GET', $this->endpoint, $payload); 146 | 147 | if ($response->getStatusCode() !== 200) { 148 | throw CouldNotGeocode::couldNotConnect(); 149 | } 150 | 151 | $reverseGeocodingResponse = json_decode($response->getBody()); 152 | 153 | if (! empty($reverseGeocodingResponse->error_message)) { 154 | throw CouldNotGeocode::serviceReturnedError($reverseGeocodingResponse->error_message); 155 | } 156 | 157 | if (! count($reverseGeocodingResponse->results)) { 158 | return $this->emptyResponse(); 159 | } 160 | 161 | return $this->formatResponse($reverseGeocodingResponse); 162 | } 163 | 164 | protected function formatResponse($response): array 165 | { 166 | $locations = array_map(function ($result) { 167 | return [ 168 | 'lat' => $result->geometry->location->lat, 169 | 'lng' => $result->geometry->location->lng, 170 | 'accuracy' => $result->geometry->location_type, 171 | 'formatted_address' => $result->formatted_address, 172 | 'viewport' => $result->geometry->viewport, 173 | 'address_components' => $result->address_components, 174 | 'partial_match' => isset($result->partial_match) ? $result->partial_match : false , 175 | 'place_id' => $result->place_id, 176 | 'types' => $result->types, 177 | ]; 178 | }, $response->results); 179 | 180 | return $locations; 181 | } 182 | 183 | protected function getRequestPayload(array $parameters): array 184 | { 185 | $parameters = array_merge([ 186 | 'key' => $this->apiKey, 187 | 'language' => $this->language, 188 | 'region' => $this->region, 189 | 'bounds' => $this->bounds, 190 | ], $parameters); 191 | 192 | if ($this->country) { 193 | $parameters = array_merge( 194 | $parameters, 195 | ['components' => 'country:'.$this->country] 196 | ); 197 | } 198 | 199 | return ['query' => $parameters]; 200 | } 201 | 202 | protected function emptyResponse(): array 203 | { 204 | return [ 205 | [ 206 | 'lat' => 0, 207 | 'lng' => 0, 208 | 'accuracy' => static::RESULT_NOT_FOUND, 209 | 'formatted_address' => static::RESULT_NOT_FOUND, 210 | 'viewport' => static::RESULT_NOT_FOUND, 211 | ], 212 | ]; 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | Logo for Geocoder 6 | 7 | 8 | 9 |

Geocode Addresses into Coordinates

10 | 11 | [![Latest Version](https://img.shields.io/github/release/spatie/geocoder.svg?style=flat-square)](https://github.com/spatie/geocoder/releases) 12 | [![MIT Licensed](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md) 13 | [![run-tests](https://github.com/spatie/geocoder/actions/workflows/run-tests.yml/badge.svg)](https://github.com/spatie/geocoder/actions/workflows/run-tests.yml) 14 | ![Check & fix styling](https://github.com/spatie/geocoder/workflows/Check%20&%20fix%20styling/badge.svg) 15 | [![Total Downloads](https://img.shields.io/packagist/dt/spatie/geocoder.svg?style=flat-square)](https://packagist.org/packages/spatie/geocoder) 16 | 17 |
18 | 19 | This package can convert any address to GPS coordinates using [Google's geocoding service](https://developers.google.com/maps/documentation/geocoding/start). Here's a quick example: 20 | 21 | ```php 22 | Geocoder::getCoordinatesForAddress('Samberstraat 69, Antwerpen, Belgium'); 23 | 24 | // will return this array 25 | [ 26 | 'lat' => 51.2343564, 27 | 'lng' => 4.4286108, 28 | 'accuracy' => 'ROOFTOP', 29 | 'formatted_address' => 'Samberstraat 69, 2060 Antwerpen, Belgium', 30 | 'viewport' => [ 31 | "northeast" => [ 32 | "lat" => 51.23570538029149, 33 | "lng" => 4.429959780291502 34 | ], 35 | "southwest" => [ 36 | "lat" => 51.2330074197085, 37 | "lng" => 4.427261819708497 38 | ] 39 | ] 40 | ] 41 | ``` 42 | 43 | ## Support us 44 | 45 | Learn how to create a package like this one, by watching our premium video course: 46 | 47 | [![Laravel Package training](https://spatie.be/github/package-training.jpg)](https://laravelpackage.training) 48 | 49 | We invest a lot of resources into creating [best in class open source packages](https://spatie.be/open-source). You can support us by [buying one of our paid products](https://spatie.be/open-source/support-us). 50 | 51 | We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on [our contact page](https://spatie.be/about-us). We publish all received postcards on [our virtual postcard wall](https://spatie.be/open-source/postcards). 52 | 53 | ## Installation 54 | 55 | You can install this package through composer. 56 | 57 | ```bash 58 | composer require spatie/geocoder 59 | ``` 60 | ## Laravel installation 61 | 62 | Though the package works fine in non-Laravel projects we included some niceties for our fellow artistans. 63 | 64 | In Laravel 5.5 the package will autoregister itself. In older versions of Laravel you must manually install the service provider and facade. 65 | 66 | ```php 67 | // config/app.php 68 | 'providers' => [ 69 | '...', 70 | Spatie\Geocoder\GeocoderServiceProvider::class 71 | ]; 72 | ``` 73 | 74 | ```php 75 | // config/app.php 76 | 'aliases' => array( 77 | ... 78 | 'Geocoder' => Spatie\Geocoder\Facades\Geocoder::class, 79 | ) 80 | ``` 81 | 82 | Next, you must publish the config file : 83 | 84 | ```bash 85 | php artisan vendor:publish --provider="Spatie\Geocoder\GeocoderServiceProvider" --tag="config" 86 | ``` 87 | 88 | This is the content of the config file: 89 | 90 | ```php 91 | return [ 92 | 93 | /* 94 | * The api key used when sending Geocoding requests to Google. 95 | */ 96 | 'key' => env('GOOGLE_MAPS_GEOCODING_API_KEY', ''), 97 | 98 | 99 | /* 100 | * The language param used to set response translations for textual data. 101 | * 102 | * More info: https://developers.google.com/maps/faq#languagesupport 103 | */ 104 | 105 | 'language' => '', 106 | 107 | /* 108 | * The region param used to finetune the geocoding process. 109 | * 110 | * More info: https://developers.google.com/maps/documentation/geocoding/intro#RegionCodes 111 | */ 112 | 'region' => '', 113 | 114 | /* 115 | * The bounds param used to finetune the geocoding process. 116 | * 117 | * More info: https://developers.google.com/maps/documentation/geocoding/intro#Viewports 118 | */ 119 | 'bounds' => '', 120 | 121 | /* 122 | * The country param used to limit results to a specific country. 123 | * 124 | * More info: https://developers.google.com/maps/documentation/javascript/geocoding#GeocodingRequests 125 | */ 126 | 'country' => '', 127 | ]; 128 | ``` 129 | 130 | ## Usage 131 | 132 | Here's how you can use the Geocoder. 133 | 134 | ```php 135 | $client = new \GuzzleHttp\Client(); 136 | 137 | $geocoder = new Geocoder($client); 138 | 139 | $geocoder->setApiKey(config('geocoder.key')); 140 | 141 | $geocoder->setCountry(config('geocoder.country', 'US')); 142 | 143 | $geocoder->getCoordinatesForAddress('Infinite Loop 1, Cupertino'); 144 | 145 | /* 146 | This function returns an array with keys 147 | "lat" => 37.331741000000001 148 | "lng" => -122.0303329 149 | "accuracy" => "ROOFTOP" 150 | "formatted_address" => "1 Infinite Loop, Cupertino, CA 95014, USA", 151 | "viewport" => [ 152 | "northeast" => [ 153 | "lat" => 37.3330546802915, 154 | "lng" => -122.0294342197085 155 | ], 156 | "southwest" => [ 157 | "lat" => 37.3303567197085, 158 | "lng" => -122.0321321802915 159 | ] 160 | ] 161 | */ 162 | ``` 163 | 164 | You can get the result back in a specific language. 165 | 166 | ```php 167 | $geocoder->setLanguage('it'); 168 | 169 | $geocoder->getCoordinatesForAddress('Infinite Loop 1, Cupertino'); 170 | 171 | /* 172 | This function returns an array with keys 173 | "lat" => 37,3318598 174 | "lng" => -122,0302485 175 | "accuracy" => "ROOFTOP" 176 | "formatted_address" => "Infinite Loop 1, 1 Infinite Loop, Cupertino, CA 95014, Stati Uniti" 177 | ... 178 | */ 179 | ``` 180 | 181 | You can also get all the results instead of the first one 182 | ```php 183 | $geocoder 184 | ->getAllCoordinatesForAddress('Infinite Loop 1, Cupertino'); 185 | 186 | /* 187 | This function returns an array of results (array of array) 188 | ^ array:2 [ 189 | 0 => array:7 [ 190 | "lat" => 37,3318115 191 | "lng" => -122,0301837 192 | "accuracy" => "ROOFTOP" 193 | "formatted_address" => "1 Infinite Loop, Cupertino, CA 95014, Stati Uniti" 194 | "viewport" => [ 195 | "northeast" => [ 196 | "lat" => 37.3330546802915, 197 | "lng" => -122.0294342197085 198 | ], 199 | "southwest" => [ 200 | "lat" => 37.3303567197085, 201 | "lng" => -122.0321321802915 202 | ] 203 | ] 204 | "place_id" => "ChIJHTRqF7e1j4ARzZ_Fv8VA4Eo" 205 | ] 206 | 1 => array:7 [ 207 | "lat" => 37,3318598 208 | "lng" => -122,0302485 209 | "accuracy" => "ROOFTOP" 210 | "formatted_address" => "Infinite Loop 1, 1 Infinite Loop, Cupertino, CA 95014, Stati Uniti" 211 | "viewport" => [ 212 | "northeast" => [ 213 | "lat" => 37.333046180291 214 | "lng" => -122.02883961971 215 | ], 216 | "southwest" => [ 217 | "lat" => 37.330348219708 218 | "lng" => -122.03153758029 219 | ] 220 | ] 221 | "place_id" => "ChIJAf9D3La1j4ARuwKZtGjgMXw" 222 | ] 223 | ] 224 | */ 225 | ``` 226 | 227 | This is how you can reverse geocode coordinates to addresses. 228 | 229 | ```php 230 | $geocoder->getAddressForCoordinates(40.714224, -73.961452); 231 | 232 | /* 233 | This function returns an array with keys 234 | "lat" => 40.7142205 235 | "lng" => -73.9612903 236 | "accuracy" => "ROOFTOP" 237 | "formatted_address" => "277 Bedford Ave, Brooklyn, NY 11211, USA", 238 | "viewport" => [ 239 | "northeast" => [ 240 | "lat" => 37.3330546802915, 241 | "lng" => -122.0294342197085 242 | ], 243 | "southwest" => [ 244 | "lat" => 37.3303567197085, 245 | "lng" => -122.0321321802915 246 | ] 247 | ] 248 | */ 249 | ``` 250 | 251 | You can also reverse geocode coordinates to all the related addresses. 252 | 253 | ```php 254 | $geocoder->getAllAddressesForCoordinates(40.714224, -73.961452); 255 | 256 | /* 257 | This function returns an array of results (array of array) 258 | array:2 [ 259 | 0 => array: 7 [ 260 | "lat" => 40.7142205 261 | "lng" => -73.9612903 262 | "accuracy" => "ROOFTOP" 263 | "formatted_address" => "277 Bedford Ave, Brooklyn, NY 11211, USA", 264 | "viewport" => [ 265 | "northeast" => [ 266 | "lat" => 37.3330546802915, 267 | "lng" => -122.0294342197085 268 | ], 269 | "southwest" => [ 270 | "lat" => 37.3303567197085, 271 | "lng" => -122.0321321802915 272 | ] 273 | ] 274 | ], 275 | 1 => array: 7 [ 276 | "lat" => 40.7142015 277 | "lng" => -73.9613077 278 | "accuracy" => "ROOFTOP" 279 | "formatted_address" => "279 Bedford Ave, Brooklyn, NY 11211, USA", 280 | "viewport" => [ 281 | "northeast" => [ 282 | "lat" => 40.715557080291, 283 | "lng" => -73.959947169708 284 | ], 285 | "southwest" => [ 286 | "lat" => 40.712859119708, 287 | "lng" => -73.962645130291 288 | ] 289 | ] 290 | ] 291 | ] 292 | */ 293 | ``` 294 | 295 | If you are using the package with Laravel, you can simply call `getCoordinatesForAddress`. 296 | 297 | ```php 298 | Geocoder::getCoordinatesForAddress('Infinite Loop 1, Cupertino'); 299 | 300 | /* 301 | This function returns an array with keys 302 | "lat" => 37.331741000000001 303 | "lng" => -122.0303329 304 | "accuracy" => "ROOFTOP" 305 | "formatted_address" => "1 Infinite Loop, Cupertino, CA 95014, Stati Uniti", 306 | "viewport" => [ 307 | "northeast" => [ 308 | "lat" => 37.3330546802915, 309 | "lng" => -122.0294342197085 310 | ], 311 | "southwest" => [ 312 | "lat" => 37.3303567197085, 313 | "lng" => -122.0321321802915 314 | ] 315 | ] 316 | */ 317 | ``` 318 | 319 | The accuracy key can contain these values: 320 | - `ROOFTOP` 321 | - `RANGE_INTERPOLATED` 322 | - `GEOMETRIC_CENTER` 323 | - `APPROXIMATE` 324 | 325 | You can read more information about these values [on the Google Geocoding API Page](https://developers.google.com/maps/documentation/geocoding/ "Google Geocoding API") 326 | 327 | When an address is not found accuracy and formatted_address will contain `result_not_found` 328 | 329 | ## Credits 330 | 331 | - [Freek Van der Herten](https://github.com/freekmurze) 332 | - [All Contributors](../../contributors) 333 | 334 | ## License 335 | 336 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 337 | --------------------------------------------------------------------------------